Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] main from itcharge:main #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 5 commits into AlgorithmAndLeetCode:main from itcharge:main
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
更新题解列表
  • Loading branch information
itcharge committed Aug 31, 2022
commit a44e315220a6d0ca2e0ef63c612fb514fc9e95ea
51 changes: 36 additions & 15 deletions Solutions/0020. 有效的括号.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,44 @@

## 题目大意

给定一个只包括 `'('`,`')'`,`'{'`,`'}'`,`'['`,`']'` 的字符串 `s` 。
**描述**:给定一个只包括 `'('`,`')'`,`'{'`,`'}'`,`'['`,`']'` 的字符串 `s` 。

要求:判断括号是否匹配。
**要求**:判断字符串 `s` 是否有效(即括号是否匹配)。

**说明**:

- 有效字符串需满足:
1. 左括号必须用相同类型的右括号闭合。
2. 左括号必须以正确的顺序闭合。

**示例**:

```Python
输入:s = "()"
输出:True


输入:s = "()[]{}"
输出:True
```

## 解题思路

括号匹配是「栈」的经典应用。
### 思路 1:栈

我们可以用栈来解决这道题。具体做法如下:
括号匹配是「栈」的经典应用。我们可以用栈来解决这道题。具体做法如下:

- 先判断一下字符串的长度是否为偶数。因为括号是成对出现的,所以字符串的长度应为偶数,可以直接判断长度为奇数的字符串不匹配。
- 如果字符串长度为奇数,则说明字符串 `s` 中的括号不匹配,直接返回 `False`。
- 使用栈 `stack` 来保存未匹配的左括号。然后依次遍历字符串 `s` 中的每一个字符。
- 如果遍历到左括号时,将其入栈。
- 如果遍历到右括号时,先看栈顶元素是否是与当前右括号相同类型的左括号。
- 如果是相同类型的左括号,则令其出栈,继续向前遍历。
- 如果不是相同类型的左括号,则说明字符串 `s` 中的括号不匹配,直接返回 `False`。
- 遍历完,还要再判断一下栈是否为空。
- 如果栈为空,则说明字符串 `s` 中的括号匹配,返回 `True`。
- 如果栈不为空,则说明字符串 `s` 中的括号不匹配,返回 `False`。
1. 先判断一下字符串的长度是否为偶数。因为括号是成对出现的,所以字符串的长度应为偶数,可以直接判断长度为奇数的字符串不匹配。如果字符串长度为奇数,则说明字符串 `s` 中的括号不匹配,直接返回 `False`。
2. 使用栈 `stack` 来保存未匹配的左括号。然后依次遍历字符串 `s` 中的每一个字符。
1. 如果遍历到左括号时,将其入栈。
2. 如果遍历到右括号时,先看栈顶元素是否是与当前右括号相同类型的左括号。
1. 如果是与当前右括号相同类型的左括号,则令其出栈,继续向前遍历。
2. 如果不是与当前右括号相同类型的左括号,则说明字符串 `s` 中的括号不匹配,直接返回 `False`。
3. 遍历完,还要再判断一下栈是否为空。
1. 如果栈为空,则说明字符串 `s` 中的括号匹配,返回 `True`。
2. 如果栈不为空,则说明字符串 `s` 中的括号不匹配,返回 `False`。

##代码
### 思路 1:代码

```Python
class Solution:
Expand Down Expand Up @@ -58,3 +74,8 @@ class Solution:
return False
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n)$。
- **空间复杂度**:$O(n)$。

51 changes: 43 additions & 8 deletions Solutions/0150. 逆波兰表达式求值.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,42 @@

## 题目大意

给定一个字符串数组,表示「逆波兰表达式」。
**描述**:给定一个字符串数组 `tokens`,表示「逆波兰表达式」。

要求:求解表达式的值。
**要求**:求解表达式的值。

**说明**:

- **逆波兰表达式**:也称为后缀表达式。
- 中缀表达式 `( 1 + 2 ) * ( 3 + 4 ) `,对应的逆波兰表达式为 ` ( ( 1 2 + ) ( 3 4 + ) * )` 。

- 1ドル \le tokens.length \le 10^4$。
- `tokens[i]` 是一个算符(`+`、`-`、`*` 或 `/`),或是在范围 $[-200, 200]$ 内的一个整数。

**示例**:

```Python
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6


输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
```

## 解题思路

### 思路 1:栈

这道题是栈的典型应用。我们先来简单介绍一下逆波兰表达式。

逆波兰表达式,也叫做后缀表达式,特点是:没有括号,运算符总是放在和它相关的操作数之后。
Expand All @@ -19,12 +49,12 @@

逆波兰表达式的计算遵循从左到右的规律。我们在计算逆波兰表达式的值时,可以使用一个栈来存放当前的操作数,从左到右依次遍历逆波兰表达式,计算出对应的值。具体操作步骤如下:

- 使用列表 `stack` 作为栈存放操作数,然后遍历表达式的字符串数组。
- 如果当前字符为运算符,则取出栈顶两个元素,在进行对应的运算之后,再将运算结果入栈。
- 如果当前字符为数字,则直接将数字入栈。
- 遍历结束后弹出栈中最后剩余的元素,这就是最终结果。
1. 使用列表 `stack` 作为栈存放操作数,然后遍历表达式的字符串数组。
2. 如果当前字符为运算符,则取出栈顶两个元素,在进行对应的运算之后,再将运算结果入栈。
3. 如果当前字符为数字,则直接将数字入栈。
4. 遍历结束后弹出栈中最后剩余的元素,这就是最终结果。

##代码
### 思路 1:代码

```Python
class Solution:
Expand All @@ -38,8 +68,13 @@ class Solution:
elif token == '*':
stack.append(stack.pop() * stack.pop())
elif token == '/':
stack.append(int(1/stack.pop()*stack.pop()))
stack.append(int(1 / stack.pop() * stack.pop()))
else:
stack.append(int(token))
return stack.pop()
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n)$。
- **空间复杂度**:$O(n)$。
66 changes: 51 additions & 15 deletions Solutions/0155. 最小栈.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,49 @@

## 题目大意

要求:设计一个「栈」。实现 `push` ,`pop` ,`top` ,`getMin` 操作,其中 `getMin` 要求能在常数时间内实现。
**要求**:设计一个「栈」。实现 `push` ,`pop` ,`top` ,`getMin` 操作,其中 `getMin` 要求能在常数时间内实现。

**说明**:

- $-2^{31} \le val \le 2^{31} - 1$。
- `pop`、`top` 和 `getMin` 操作总是在非空栈上调用
- `push`,`pop`,`top` 和 `getMin` 最多被调用 3ドル * 10^4$ 次。

**示例**:

```Python
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
```

## 解题思路

题目要求在常数时间内获取最小值,所以我们不能在 `getMin` 操作时,再去计算栈中的最小值。而是应该在 `push`、`pop` 操作时就已经计算好了最小值。
题目要求在常数时间内获取最小值,所以我们不能在 `getMin` 操作时,再去计算栈中的最小值。而是应该在 `push`、`pop` 操作时就已经计算好了最小值。我们有两种思路来解决这道题。

我们有两种思路来解决这道题。
### 思路 1:辅助栈

思路一:使用辅助栈保存当前栈中的最小值。在元素入栈出栈时,两个栈同步保持插入和删除。具体做法如下:
使用辅助栈保存当前栈中的最小值。在元素入栈出栈时,两个栈同步保持插入和删除。具体做法如下:

- `push` 操作:当一个元素入栈时,取辅助栈的栈顶存储的最小值,与当前元素进行比较得出最小值,将最小值插入到辅助栈中;该元素也插入到正常栈中。
- `pop` 操作:当一个元素要出栈时,将辅助栈的栈顶元素一起弹出。
- `top` 操作:返回正常栈的栈顶元素值。
- `getMin` 操作:返回辅助栈的栈顶元素值。

思路二:使用一个栈,保存元组:(当前元素值,当前栈内最小值)。具体操作如下:

- `push` 操作:如果栈不为空,则判断当前元素值与栈顶元素所保存的最小值,并更新当前最小值,然后将新元素和当前最小值组成的元组保存到栈中。
- `pop`操作:正常出栈,即将栈顶元素弹出。
- `top` 操作:返回栈顶元素保存的值。
- `getMin` 操作:返回栈顶元素保存的最小值。

## 代码

- 思路一:
### 思路 1:代码

```Python
class MinStack:
Expand Down Expand Up @@ -57,7 +75,21 @@ class MinStack:
return self.minstack[-1]
```

- 思路二:
### 思路 1:复杂度分析

- **时间复杂度**:$O(1)$。栈的插入、删除、读取操作都是 $O(1)$。
- **空间复杂度**:$O(n)$。其中 $n$ 为总操作数。

### 思路 2:单个栈

使用单个栈,保存元组:(当前元素值,当前栈内最小值)。具体操作如下:

- `push` 操作:如果栈不为空,则判断当前元素值与栈顶元素所保存的最小值,并更新当前最小值,然后将新元素和当前最小值组成的元组保存到栈中。
- `pop`操作:正常出栈,即将栈顶元素弹出。
- `top` 操作:返回栈顶元素保存的值。
- `getMin` 操作:返回栈顶元素保存的最小值。

### 思路 2:代码

```Python
class MinStack:
Expand Down Expand Up @@ -93,3 +125,7 @@ class MinStack:
return self.stack[-1].min
```

### 思路 2:复杂度分析

- **时间复杂度**:$O(1)$。栈的插入、删除、读取操作都是 $O(1)$。
- **空间复杂度**:$O(n)$。其中 $n$ 为总操作数。
48 changes: 37 additions & 11 deletions Solutions/0227. 基本计算器 II.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,49 @@

## 题目大意

给定一个字符串表达式 `s`,表达式中所有整数为非负整数,运算符只有 `+`、`-`、`*`、`/`,没有括号。
**描述**:给定一个字符串表达式 `s`,表达式中所有整数为非负整数,运算符只有 `+`、`-`、`*`、`/`,没有括号。

要求:实现一个基本计算器来计算并返回它的值。
**要求**:实现一个基本计算器来计算并返回它的值。

**说明**:

- 1ドル \le s.length \le 3 * 10^5$。
- `s` 由整数和算符(`+`、`-`、`*`、`/`)组成,中间由一些空格隔开。
- `s` 表示一个有效表达式。
- 表达式中的所有整数都是非负整数,且在范围 $[0, 2^{31} - 1]$ 内。
- 题目数据保证答案是一个 32-bit 整数。

**示例**:

```Python
输入:s = "3+2*2"
输出:7


输入:s = " 3/2 "
输出:1
```

## 解题思路

### 思路 1:栈

计算表达式中,乘除运算优先于加减运算。我们可以先进行乘除运算,再将进行乘除运算后的整数值放入原表达式中相应位置,再依次计算加减。

可以考虑使用一个栈来保存进行乘除运算后的整数值。正整数直接压入栈中,负整数,则将对应整数取负号,再压入栈中。这样最终计算结果就是栈中所有元素的和。

具体做法:

- 遍历字符串 `s`,使用变量 `op` 来标记数字之前的运算符,默认为 `+`。
- 如果遇到数字,继续向后遍历,将数字进行累积,得到完整的整数 num。判断当前 op 的符号。
- 如果 `op` 为 `+`,则将 `num` 压入栈中。
- 如果 `op` 为 `-`,则将 `-num` 压入栈中。
- 如果 `op` 为 `*`,则将栈顶元素 `top` 取出,计算 `top * num`,并将计算结果压入栈中。
- 如果 `op` 为 `/`,则将栈顶元素 `top` 取出,计算 `int(top / num)`,并将计算结果压入栈中。
- 如果遇到 `+`、`-`、`*`、`/` 操作符,则更新 `op`。
- 最后将栈中整数进行累加,并返回结果。
1. 遍历字符串 `s`,使用变量 `op` 来标记数字之前的运算符,默认为 `+`。
2. 如果遇到数字,继续向后遍历,将数字进行累积,得到完整的整数 num。判断当前 op 的符号。
1. 如果 `op` 为 `+`,则将 `num` 压入栈中。
2. 如果 `op` 为 `-`,则将 `-num` 压入栈中。
3. 如果 `op` 为 `*`,则将栈顶元素 `top` 取出,计算 `top * num`,并将计算结果压入栈中。
4. 如果 `op` 为 `/`,则将栈顶元素 `top` 取出,计算 `int(top / num)`,并将计算结果压入栈中。
3. 如果遇到 `+`、`-`、`*`、`/` 操作符,则更新 `op`。
4. 最后将栈中整数进行累加,并返回结果。

##代码
### 思路 1:代码

```Python
class Solution:
Expand Down Expand Up @@ -60,3 +81,8 @@ class Solution:
return sum(stack)
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n)$。
- **空间复杂度**:$O(n)$。

55 changes: 39 additions & 16 deletions Solutions/0316. 去除重复字母.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,50 @@

## 题目大意

给定一个字符串 `s`。
**描述**:给定一个字符串 `s`。

要求:去除字符串中重复的字母,使得每个字母只出现一次。需要保证 **「返回结果的字典序最小(要求不能打乱其他字符的相对位置)」**。
**要求**:去除字符串中重复的字母,使得每个字母只出现一次。需要保证 **「返回结果的字典序最小(要求不能打乱其他字符的相对位置)」**。

**说明**:

- 1ドル \le s.length \le 10^4$。
- `s` 由小写英文字母组成。

**示例**:

```Python
输入:s = "bcabc"
输出:"abc"


输入:s = "cbacdcbc"
输出:"acdb"
```

## 解题思路

### 思路 1:哈希表 + 单调栈

针对题目的三个要求:去重、不能打乱其他字符顺序、字典序最小。我们来一一分析。

1. 去重:可以通过 **「使用哈希表存储字母出现次数」** 的方式,将每个字母出现的次数统计起来,再遍历一遍,去除重复的字母。
2. 不能打乱其他字符顺序:按顺序遍历,将非重复的字母存储到答案数组或者栈中,最后再拼接起来,就能保证不打乱其他字符顺序。
3. 字典序最小:意味着字典序小的字母应该尽可能放在前面。
- 对于第 `i` 个字符 `s[i]` 而言,如果第 `0` ~ `i - 1` 之间的某个字符 `s[j]` 在 `s[i]` 之后不再出现了,那么 `s[j]` 必须放到 `s[i]` 之前。
- 而如果 `s[j]` 在之后还会出现,并且 `s[j]` 的字典序大于 `s[i]`,我们则可以先舍弃 `s[j]`,把 `s[i]` 尽可能的放到前面。后边再考虑使用 `s[j]` 所对应的字符。
1. **去重**:可以通过 **「使用哈希表存储字母出现次数」** 的方式,将每个字母出现的次数统计起来,再遍历一遍,去除重复的字母。
2. **不能打乱其他字符顺序**:按顺序遍历,将非重复的字母存储到答案数组或者栈中,最后再拼接起来,就能保证不打乱其他字符顺序。
3. **字典序最小**:意味着字典序小的字母应该尽可能放在前面。
1. 对于第 `i` 个字符 `s[i]` 而言,如果第 `0` ~ `i - 1` 之间的某个字符 `s[j]` 在 `s[i]` 之后不再出现了,那么 `s[j]` 必须放到 `s[i]` 之前。
2. 而如果 `s[j]` 在之后还会出现,并且 `s[j]` 的字典序大于 `s[i]`,我们则可以先舍弃 `s[j]`,把 `s[i]` 尽可能的放到前面。后边再考虑使用 `s[j]` 所对应的字符。

要满足第 3 条需求,我们可以使用 **「单调栈」** 来解决。我们使用单调栈存储 `s[i]` 之前出现的非重复、并且字典序最小的字符序列。整个算法步骤如下:

- 先遍历一遍字符串,用哈希表 `letter_counts` 统计出每个字母出现的次数。
- 然后使用单调递减栈保存当前字符之前出现的非重复、并且字典序最小的字符序列。
要满足第 3 条需求,我们可以使用 **「单调栈」** 来解决。我们使用单调栈存储 `s[i]` 之前出现的非重复、并且字典序最小的字符序列。整个算法步骤如下:

- 当遍历到 `s[i]` 时,如果 `s[i]` 没有在栈中出现过:
- 则比较 `s[i]` 和栈顶元素 `stack[-1]` 的字典序。如果 `s[i]` 的字典序小于栈顶元素 `stack[-1]`,并且栈顶元素之后的出现次数大于 `0`,则将栈顶元素弹出。
- 然后继续判断 `s[i]` 和栈顶元素 `stack[-1]`,并且知道栈顶元素出现次数为 `0` 时停止弹出。此时将 `s[i]` 添加到单调栈中。
- 从哈希表 `letter_counts` 中减去 `s[i]` 出现的次数,继续遍历。
- 最后将单调栈中的字符依次拼接为答案字符串,并返回。
1. 先遍历一遍字符串,用哈希表 `letter_counts` 统计出每个字母出现的次数。
2. 然后使用单调递减栈保存当前字符之前出现的非重复、并且字典序最小的字符序列。
3. 当遍历到 `s[i]` 时,如果 `s[i]` 没有在栈中出现过:
1. 比较 `s[i]` 和栈顶元素 `stack[-1]` 的字典序。如果 `s[i]` 的字典序小于栈顶元素 `stack[-1]`,并且栈顶元素之后的出现次数大于 `0`,则将栈顶元素弹出。
2. 然后继续判断 `s[i]` 和栈顶元素 `stack[-1]`,并且知道栈顶元素出现次数为 `0` 时停止弹出。此时将 `s[i]` 添加到单调栈中。
4. 从哈希表 `letter_counts` 中减去 `s[i]` 出现的次数,继续遍历。
5. 最后将单调栈中的字符依次拼接为答案字符串,并返回。

##代码
### 思路 1:代码

```Python
class Solution:
Expand All @@ -53,6 +71,11 @@ class Solution:
return ''.join(stack)
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n)$。
- **空间复杂度**:$O(|\sum|),ドル其中 $\sum$ 为字符集合,$|\sum|$ 为字符种类个数。由于栈中字符不能重复,因此栈中最多有 $|\sum|$ 个字符。

## 参考资料

- 【题解】[去除重复数组 - 去除重复字母 - 力扣(LeetCode)](https://leetcode.cn/problems/remove-duplicate-letters/solution/qu-chu-zhong-fu-shu-zu-by-lu-shi-zhe-sokp/)
Loading

AltStyle によって変換されたページ (->オリジナル) /