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 all commits
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
103 changes: 74 additions & 29 deletions Contents/03.Stack/01.Stack-Basic/01.Stack-Basic.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -185,28 +185,44 @@ class Stack:

#### 3.1.2 题目大意

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

要求:判断括号是否匹配。如果匹配,返回 `True`,否则返回 `False`。
**要求**:判断字符串 `s` 是否有效(即括号是否匹配)。

**说明**:

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

**示例**:

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


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

#### 3.2.3 解题思路

括号匹配是「栈」的经典应用。
##### 思路 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`。

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

```Python
class Solution:
Expand Down Expand Up @@ -238,6 +254,11 @@ class Solution:
return False
```

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

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

### 3.2 表达式求值问题

#### 3.2.1 题目链接
Expand All @@ -246,30 +267,49 @@ class Solution:

#### 3.2.2 题目大意

给定一个字符串表达式 `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
```

#### 3.2.3 解题思路

表达式求值问题也是栈的经典应用。
##### 思路 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. 最后将栈中整数进行累加,并返回结果。

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

```Python
class Solution:
Expand Down Expand Up @@ -303,6 +343,11 @@ class Solution:
return sum(stack)
```

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

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

## 参考资料

- 【书籍】数据结构与算法 Python 语言描述 - 裘宗燕 著
Expand Down
81 changes: 61 additions & 20 deletions Contents/03.Stack/02.Monotone-Stack/01.Monotone-Stack.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -75,30 +75,48 @@

所以单调栈一般用于解决一下几种问题:

- 寻找左侧第一个比当前元素大的元素
- 寻找左侧第一个比当前元素小的元素
- 寻找右侧第一个比当前元素大的元素
- 寻找右侧第一个比当前元素小的元素
- 寻找左侧第一个比当前元素大的元素
- 寻找左侧第一个比当前元素小的元素
- 寻找右侧第一个比当前元素大的元素
- 寻找右侧第一个比当前元素小的元素

下面分别说一下这几种问题的求解方法。

### 2.1 寻找左侧第一个比当前元素大的元素

- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素左侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素大的元素。
- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):
- 一个元素左侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。
- 如果插入时的栈为空,则说明左侧不存在比当前元素大的元素。


### 2.2 寻找左侧第一个比当前元素小的元素

- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素左侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素小的元素。
- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):
- 一个元素左侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。
- 如果插入时的栈为空,则说明左侧不存在比当前元素小的元素。


### 2.3 寻找右侧第一个比当前元素大的元素

- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「弹出单调递增栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。
- 从右到左遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素大的元素。
- 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):
- 一个元素右侧第一个比它大的元素就是将其「弹出单调递增栈」时即将插入的元素。
- 如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。

- 从右到左遍历元素,构造单调递增栈(从栈顶到栈底递增):
- 一个元素右侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。
- 如果插入时的栈为空,则说明右侧不存在比当前元素大的元素。


### 2.4 寻找右侧第一个比当前元素小的元素

- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「弹出单调递减栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。
- 从右到左遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素小的元素。
- 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):
- 一个元素右侧第一个比它小的元素就是将其「弹出单调递减栈」时即将插入的元素。
- 如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。

- 从右到左遍历元素,构造单调递减栈(从栈顶到栈底递减):
- 一个元素右侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。
- 如果插入时的栈为空,则说明右侧不存在比当前元素小的元素。


上边的分类解法有点绕口,可以简单记为以下条规则:

Expand Down Expand Up @@ -192,26 +210,44 @@ class Solution:

#### 4.2.2 题目大意

给定一个列表 `temperatures`,每一个位置对应每天的气温。
**描述**:给定一个列表 `temperatures`,`temperatures[i]` 表示第 `i` 天的气温。

**要求**:输出一个列表,列表上每个位置代表「如果要观测到更高的气温,至少需要等待的天数」。如果之后的气温不再升高,则用 `0` 来代替。

**说明**:

- 1ドル \le temperatures.length \le 10^5$。
- 30ドル \le temperatures[i] \le 100$。

要求:输出一个列表,列表上每个位置代表如果要观测到更高的气温,至少需要等待的天数。如果之后的气温不再升高,则用 `0` 来代替。
**示例**:

```Python
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]


输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
```

#### 4.2.3 解题思路

题目的意思实际上就是给定一个数组,每个位置上有整数值。对于每个位置,在该位置右侧找到第一个比当前元素更大的元素。求「该元素」与「右侧第一个比当前元素更大的元素」之间的距离,将所有距离保存为数组返回结果。

最简单的思路是对于每个温度值,向后依次进行搜索,找到比当前温度更高的值。

更好的方式使用「单调递增栈」。栈中保存元素的下标。
更好的方式使用「单调递增栈」,栈中保存元素的下标。

##### 思路 1:单调栈

- 首先,将答案数组 `ans` 全部赋值为 0。然后遍历数组每个位置元素。
- 如果栈为空,则将当前元素的下标入栈。
- 如果栈不为空,且当前数字大于栈顶元素对应数字,则栈顶元素出栈,并计算下标差。
- 此时当前元素就是栈顶元素的下一个更高值,将其下标差存入答案数组 `ans` 中保存起来,判断栈顶元素。
- 直到当前数字小于或等于栈顶元素,则停止出栈,将当前元素下标入栈。
- 最后输出答案数组 `ans`。
1. 首先,将答案数组 `ans` 全部赋值为 0。然后遍历数组每个位置元素。
2. 如果栈为空,则将当前元素的下标入栈。
3. 如果栈不为空,且当前数字大于栈顶元素对应数字,则栈顶元素出栈,并计算下标差。
4. 此时当前元素就是栈顶元素的下一个更高值,将其下标差存入答案数组 `ans` 中保存起来,判断栈顶元素。
5. 直到当前数字小于或等于栈顶元素,则停止出栈,将当前元素下标入栈。
6. 最后输出答案数组 `ans`。

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

```Python
class Solution:
Expand All @@ -227,6 +263,11 @@ class Solution:
return ans
```

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

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

## 参考资料

- 【博文】[动画:什么是单调栈?_- 吴师兄学编程](https://www.cxyxiaowu.com/450.html)
Expand Down
Loading

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