This commit is contained in:
chefyuan
2021-03-20 12:38:26 +08:00
parent 1fc9cabcf2
commit 4496ab0198
88 changed files with 2 additions and 3429 deletions

View File

@@ -0,0 +1,63 @@
# 删除相邻重复对
今天给大家带来一个栈的经典题目,删除字符串中的相邻重复项,下面我们先来看一下题目描述。
给出由小写字母组成的字符串S重复项操作会选择**两个相邻且相同**的字母,并删除他们。
在S上反复执行重复项删除操作直到无法继续删除。在完成所有重复项删除操作后返回最终字符串。答案保证唯一
示例1
> 输入“abbaca”
> 输出”ca“
我们在之前的文章中介绍过删除重复项的思想,当时我们介绍的重复项可能是两个或更多,今天的题目更加简单是两字母相邻且相同。这个题目我们可以使用双指针思想解决,用来判断两个字符是否相同,但是我们这个板块的主题是栈和队列,那么我们就详细介绍一下如何用栈解答这个题目。
## 解题思路:
我们将字符入栈,然后新的字符入栈之前先于栈顶元素对比,判断是否和栈顶元素一致,如果一致则栈顶元素出栈,指针移到下一位,则就实现了去除重复元素。如果和栈顶元素不同或栈为空则将当前元素入栈。直至字符串遍历结束,另外我们需要注意的是栈是先进后出,最后我们元素出栈的时候,我们需要对字符串反转一下才为我们的答案。
![删除重复元素对](E:\Typora笔记\CSDN\leetcode通关笔记\博客动图\删除重复元素对.gif)
```java
class Solution {
public String removeDuplicates(String S) {
Stack<Character> stack = new Stack<>();
char[] s = S.toCharArray();//先将字符串变成字符数组
//特殊情况
if (S.length() == 0 || S.length() == 1) {
return S;
}
//遍历数组
for (int i= 0; i<S.length(); i++) {
//为空或者和栈顶元素不同时入栈
if(stack.isEmpty() || s[i] != stack.peek()) {
stack.push(s[i]);
}
//相同出栈
else {
stack.pop();
}
}
StringBuilder str = new StringBuilder();
//字符出栈
while (!stack.isEmpty()) {
str.append(stack.pop());
}
//翻转字符并返回
return str.reverse().toString();
}
}
```
当然这个题目也可以用 set 来做,大家可以随意发挥

View File

@@ -0,0 +1,109 @@
#### 20. 有效的括号
今天我们开始了一个新的模块,栈和队列,另外昨天肝了一篇栈和队列的文章,大家可以先去了解以下,今天我们先来一道经典简单题热热身。大家一定要记得打卡,这个题目是真不错。
> 文章里的所有题目都是经过认真挑选的并且所有代码都经过测试大家可以放心食用。
题目描述
给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
> 输入: "()"
> 输出: true
示例 2:
> 输入: "(]"
> 输出: false
示例 3:
> 输入: "()]"
> 输出: false
示例4
> 输入:"()["
>
> 输出:false
我这里用了两种方法进行解决第一种是利用ArrayList第二种是利用栈今天主要讲 一下用栈的方法。思路很简单我们遇到左括号就将其入栈遇到右括号就和栈顶元素进行比较如果是对应的则pop栈顶元素不对应直接返回false即可。另外我们还需要考虑的就是示例3和示例4这两种情况需要我们好好思考一下。
下面我们直接上动图。
![合法的括号](E:\Typora笔记\CSDN\leetcode通关笔记\博客动图\合法的括号.gif)
题目代码:
```java
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
//循环遍历字符串
for(char ch : s.toCharArray()){
//入栈的三种情况
if (ch == '(' || ch == '[' || ch == '{') {
stack.push(ch);
}
//右括号对比,其中注意为空的情况
if (ch == ')') {
if( stack.isEmpty() || stack.pop() != '(') {
return false;
}
}
if (ch == ']') {
if (stack.isEmpty() || stack.pop() != '[') {
return false;
}
}
if (ch == '}') {
if (stack.isEmpty() || stack.pop() != '{') {
return false;
}
}
}
//遍历结束的情况
if (!stack.isEmpty()) {
return false;
}
return true;
}
}
```
另外我们看下另一种方法,这个方法很有趣,,我们遇到 [ 时,则入栈 ' ] ' ,这样当我们遇到 ] 时只需判断栈顶元素是否和其一致即可,一致则出,继续遍历下一个,否则返回 false 。
这个方法有些巧妙,大家第一次看时可能不是那么容易理解,所以大家可以自己打一下,动脑子想一下代码逻辑。
```java
class Solution {
public boolean isValid(String s) {
LinkedList<Character> stack = new LinkedList<>();
//遍历字符串
for (char ch : s.toCharArray()) {
//遍历到左括号时右括号入栈,右括号来对比时,只需要对比是否相同。
if (ch == '[') stack.push(']');
else if (ch == '(') stack.push(')');
else if (ch == '{') stack.push('}');
//当ch为右括号时如果为空或不对应则返回false;
else if (stack.isEmpty() || ch != stack.pop()) return false;
}
return stack.isEmpty();//最后判断是否为空。
}
}
```

View File

@@ -0,0 +1,81 @@
今天给大家带来一个有意思的题目思路很easy但是刚刷题的小伙伴示例理解起来可能会有点费劲花里胡哨一大堆是啥意思啊。在之前的文章《不知道这篇文章合不合你的胃口》中写了栈是先进后出队列是先进先出。本题让我们用两个先进后出的栈完成一个先进先出的队列。我们应该怎么实现呢
废话不多说,大家看图
![栈实现队列](E:\Typora笔记\CSDN\leetcode通关笔记\博客动图\栈实现队列.gif)
这就是具体思路,然后我们来看一下题目示例及官方提供的函数都是什么意思。
```java
class CQueue {
//创建队列
public CQueue() {
}
//入队
public void appendTail(int value) {
}
//出队
public int deleteHead() {
}
}
```
示例 1
```java
输入
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出[null,null,3,-1]
```
示例 2
```java
输入
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出[null,-1,null,null,5,2]
```
其实也很容易理解输入有两行第一行为执行的函数Cqueue代表创建队列(代表我们初始化两个栈)appendTail代表入队操作代表stackA入栈deleteHead代表出队操作代表我们stackB出栈
第二行输入代表值分别给每个函数传入的参数我们发现只有appendTail函数下有对应值因为只有该函数传入参数。
大家可以点击该链接[剑指 Offer 09. 用两个栈实现队列](https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/)去实现一下,下面我们看代码。
```java
class CQueue {
//初始化两个栈
Stack<Integer> stack1,stack2;
public CQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
//入队,我们往第一个栈压入值
public void appendTail (int value) {
stack1.push(value);
}
//出队
public int deleteHead() {
//大家可以自己思考一下为什么if条件为stack2.isEmpty(),细节所在
if (stack2.isEmpty()) {
//如果此时A栈没有值则直接-1我们可以看示例
if (stack1.isEmpty()) {
return -1;
}
//将A栈的值压入B栈中
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
```

View File

@@ -0,0 +1,91 @@
# 移除K位数字
今天给大家带来一个栈的中等题目移掉K位数字题目很简单但是很有趣。另外明天继续给大家带来一道栈和队列题目困难那么咱们的栈和队列模块就结束啦下周开始整字符串的题目啦
### 题目描述
给定一个以字符串表示的非负整数 num移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
> num 的长度小于 10002 且 ≥ k。
> num 不会包含任何前导零。
示例 1 :
> 输入: num = "1432219", k = 3
> 输出: "1219"
> 解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :
> 输入: num = "10200", k = 1
> 输出: "200"
> 解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
> 输入: num = "10", k = 2
> 输出: "0"
> 解释: 从原数字移除所有的数字剩余为空就是0
题目很容易理解,而且也很容易实现,因为在示例中几乎把所有特殊情况都进行了举例,我们直接代码实现就好啦。
### 栈(贪心)
下面我们来看一下用栈的解题思路因为我们需要删除掉K位数字得到最小值那么我们需要注意的是删除的数字应该尽量在高位则当前位小于前一位时对前一位出栈当前位入栈。大家思考一下思路是不是这样呢
另外我们需要注意的是仅删除K位数字得到最小值比如54321我们删除3位得到21。但是刚才我们说当前位小于前一位时则前一位出栈当前位入栈所以我们需要加上删除K位的规则。
废话不多说我们直接上动图,把该题吃透!
![移除K位数字](E:\Typora笔记\CSDN\leetcode通关笔记\博客动图\移除K位数字.gif)
PPT中的文字
> 这里需要注意的是我们不需要将0入栈因为0如果处于栈底没有比它更小的值所以它不会被移除我们只有在最后才有机会处理它。因为我们的010 = 10 首位0是需要在最后去掉的。所以我们这里可以直接不让其入栈continue掉这次循环也不改变K值这样我们最后出栈处理时就不用考虑啦。这样逻辑就比官方题解好理解一些也简洁一些。
> 这里需要注意的是我们的K值还为2我们目前仅删除2位数字但是我们需要删除4位但是后面的几位都是当前位大于前一位。所以我们需要在遍历结束后再移除后面最大的两位数字
```java
class Solution {
public String removeKdigits(String num, int k) {
//特殊情况全部删除
if (num.length() == k) {
return "0";
}
char[] s = num.toCharArray();
Stack<Character> stack = new Stack<>();
//遍历数组
for (Character i : s) {
//移除元素的情况k--
while (!stack.isEmpty() && i < stack.peek() && k > 0) {
stack.pop();
k--;
}
//栈为空且当前位为0时我们不需要将其入栈
if (stack.isEmpty() && i == '0') {
continue;
}
stack.push(i);
}
while (k > 0) {
stack.pop();
k--;
}
//这个是最后栈为空时删除一位比如我们的10删除一位为0按上面逻辑我们会返回"",所以我们让其返回"0"
if (stack.isEmpty()) {
return "0";
}
//反转并返回字符串
StringBuilder str = new StringBuilder();
while (!stack.isEmpty()) {
str.append(stack.pop());
}
return str.reverse().toString();
}
}
```
这个题目也是很不错的,题目是精心挑选的,然后动图里面的例子也是精心构思过的。所以大家记得打卡呀!

View File

@@ -0,0 +1,13 @@
# 队列实现栈
我们昨天实现了如何用两个栈实现队列,原理很简单,今天我们来实现一下如何用队列实现栈。
其实原理也很简单,我们利用队列先进先出的特点,每次队列模拟入栈时,我们先将队列之前入队的元素都出列,仅保留最后一个进队的元素。
然后再重新入队这样就实现了颠倒队列中的元素。比如我们首先入队1然后再入队2我们需要将元素1出队然后再重新入队则实现了队列内元素序列变成了2,1。
废话不多说,我们继续看动图
![队列实现栈](E:\Typora笔记\CSDN\leetcode通关笔记\博客动图\队列实现栈.gif)
下面我们来看一下题目代码,也是很容易理解。