Skip to content

Commit 67d6e53

Browse files
committed
更新题解列表
1 parent 298eb25 commit 67d6e53

File tree

4 files changed

+207
-49
lines changed

4 files changed

+207
-49
lines changed

Solutions/0438. 找到字符串中所有字母异位词.md

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,55 @@
99

1010
## 题目大意
1111

12-
给定两个字符串 `s``p`
12+
**描述**给定两个字符串 $s$$p$
1313

14-
要求:找到 `s` 中所有 `p` 的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
14+
**要求**:找到 $s$ 中所有 $p$ 的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
1515

16-
- 异位词:指由相同字母重排列形成的字符串(包括相同的字符串)。
16+
**说明**
17+
18+
- **异位词**:指由相同字母重排列形成的字符串(包括相同的字符串)。
19+
- $1 <= s.length, p.length <= 3 * 10^4$。
20+
- $s$ 和 $p$ 仅包含小写字母。
21+
22+
**示例**
23+
24+
- 示例 1:
25+
26+
```python
27+
输入: s = "cbaebabacd", p = "abc"
28+
输出: [0,6]
29+
解释:
30+
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
31+
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
32+
```
33+
34+
- 示例 2:
35+
36+
```python
37+
输入: s = "abab", p = "ab"
38+
输出: [0,1,2]
39+
解释:
40+
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
41+
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
42+
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
43+
```
1744

1845
## 解题思路
1946

20-
维护一个固定长度为 `len(p)` 的滑动窗口。于是问题的难点变为了如何判断 `s` 的子串和 `p` 是异位词。可以使用两个字典来分别存储 `s` 的子串中各个字符个数和 `p` 中各个字符个数。如果两个字典对应的键值全相等,则说明 `s` 的子串和 `p` 是异位词。但是这样每一次比较的操作时间复杂度是 $O(n)$,我们可以通过在滑动数组中逐字符比较的方式来减少两个字典之间相互比较的复杂度,并用 `valid` 记录经过验证的字符个数。整个算法步骤如下:
47+
### 思路 1:滑动窗口
2148

22-
- 使用哈希表 `need` 记录 `p` 中各个字符出现次数。使用字典 `window` 记录 `s` 的子串中各个字符出现的次数。使用数组 `res` 记录答案。使用 `valid` 记录 `s` 的子串中经过验证的字符个数。使用 `window_size` 表示窗口大小,值为 `len(p)`。使用两个指针 `left``right`。分别指向滑动窗口的左右边界。
23-
- 一开始,`left``right` 都指向 `0`
24-
- 如果 `s[right]` 出现在 `need` 中,将最右侧字符 `s[right]` 加入当前窗口 `window` 中,记录该字符个数。并验证该字符是否和 `need` 中个对应字符个数相等。如果相等则验证的字符个数 +1,即 `valid += 1`
25-
- 如果该窗口字符长度大于等于 `window_size` 个,即 `right - left + 1 >= window_size`。则不断右移 `left`,缩小滑动窗口长度。
26-
- 如果验证字符个数 `valid` 等于窗口长度 `window_size`,则 `s[left, right + 1]``p` 的异位词,所以将 `left` 加入到答案数组中。
27-
- 如果`s[left]``need` 中,则更新窗口中对应字符的个数,同时维护 `valid` 值。
28-
- 右移 `right`,直到 `right >= len(nums)` 结束。
29-
- 输出答案数组 `res`
49+
维护一个固定长度为 $len(p)$ 的滑动窗口。于是问题的难点变为了如何判断 $s$ 的子串和 $p$ 是异位词。可以使用两个字典来分别存储 $s$ 的子串中各个字符个数和 $p$ 中各个字符个数。如果两个字典对应的键值全相等,则说明 $s$ 的子串和 $p$ 是异位词。但是这样每一次比较的操作时间复杂度是 $O(n)$,我们可以通过在滑动数组中逐字符比较的方式来减少两个字典之间相互比较的复杂度,并用 $valid$ 记录经过验证的字符个数。整个算法步骤如下:
3050

31-
## 代码
51+
- 使用哈希表 $need$ 记录 $p$ 中各个字符出现次数。使用字典 $window$ 记录 $s$ 的子串中各个字符出现的次数。使用数组 $res$ 记录答案。使用 $valid$ 记录 $s$ 的子串中经过验证的字符个数。使用 $window\underline{}size$ 表示窗口大小,值为 $len(p)$。使用两个指针 $left$、$right$。分别指向滑动窗口的左右边界。
52+
- 一开始,$left$、$right$ 都指向 $0$。
53+
- 如果 $s[right]$ 出现在 $need$ 中,将最右侧字符 $s[right]$ 加入当前窗口 $window$ 中,记录该字符个数。并验证该字符是否和 $need$ 中个对应字符个数相等。如果相等则验证的字符个数加 $1$,即 `valid += 1`
54+
- 如果该窗口字符长度大于等于 $window\underline{}size$ 个,即 $right - left + 1 \ge window\underline{}size$。则不断右移 $left$,缩小滑动窗口长度。
55+
- 如果验证字符个数 $valid$ 等于窗口长度 $window\underline{}size$,则 $s[left, right + 1]$ 为 $p$ 的异位词,所以将 $left$ 加入到答案数组中。
56+
- 如果$s[left]$ 在 $need$ 中,则更新窗口中对应字符的个数,同时维护 $valid$ 值。
57+
- 右移 $right$,直到 $right \ge len(nums)$ 结束。
58+
- 输出答案数组 $res$。
59+
60+
### 思路 1:代码
3261

3362
```python
3463
class Solution:
@@ -60,3 +89,8 @@ class Solution:
6089
return res
6190
```
6291

92+
### 思路 1:复杂度分析
93+
94+
- **时间复杂度**:$O(n + m + |\sum|)$,其中 $n$、$m$ 分别为字符串 $s$、$p$ 的长度,$\sum$ 为字符集,本题中 $|\sum| = 26$。
95+
- **空间复杂度**:$|\sum|$。
96+

Solutions/1051. 高度检查器.md

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,106 @@
99

1010
## 题目大意
1111

12-
**描述**
12+
**描述**学校打算为全体学生拍一张年度纪念照。根据要求,学生需要按照 非递减 的高度顺序排成一行。
1313

14-
**要求**
14+
排序后的高度情况用整数数组 $expected$ 表示,其中 $expected[i]$ 是预计排在这一行中第 $i$ 位的学生的高度(下标从 $0$ 开始)。
15+
16+
给定一个整数数组 $heights$ ,表示当前学生站位的高度情况。$heights[i]$ 是这一行中第 $i$ 位学生的高度(下标从 $0$ 开始)。
17+
18+
**要求**:返回满足 $heights[i] \ne expected[i]$ 的下标数量 。
1519

1620
**说明**
1721

18-
-
22+
- $1 \le heights.length \le 100$。
23+
- $1 \le heights[i] \le 100$。
1924

2025
**示例**
2126

2227
- 示例 1:
2328

2429
```python
30+
输入:heights = [1,1,4,2,1,3]
31+
输出:3
32+
解释:
33+
高度:[1,1,4,2,1,3]
34+
预期:[1,1,1,2,3,4]
35+
下标 245 处的学生高度不匹配。
2536
```
2637

2738
- 示例 2:
2839

2940
```python
41+
输入:heights = [5,1,2,3,4]
42+
输出:5
43+
解释:
44+
高度:[5,1,2,3,4]
45+
预期:[1,2,3,4,5]
46+
所有下标的对应学生高度都不匹配。
3047
```
3148

3249
## 解题思路
3350

34-
### 思路 1:
51+
### 思路 1:排序算法
52+
53+
1. 将数组 $heights$ 复制一份,记为 $expected$。
54+
2. 对数组 $expected$ 进行排序。
55+
3. 排序之后,对比并统计 $heights[i] \ne expected[i]$ 的下标数量,记为 $ans$。
56+
4. 返回 $ans$。
3557

3658
### 思路 1:代码
3759

3860
```Python
61+
class Solution:
62+
def heightChecker(self, heights: List[int]) -> int:
63+
expected = sorted(heights)
64+
65+
ans = 0
66+
for i in range(len(heights)):
67+
if expected[i] != heights[i]:
68+
ans += 1
69+
return ans
3970
```
4071

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

43-
- **时间复杂度**
44-
- **空间复杂度**
74+
- **时间复杂度**:$O(n \times \log n)$,其中 $n$ 为数组 $heights$ 的长度。
75+
- **空间复杂度**:$O(n)$。
76+
77+
### 思路 2:计数排序
4578

46-
### 思路 2:
79+
题目中 $heights[i]$ 的数据范围为 $[1, 100]$,所以我们可以使用计数排序。
4780

4881
### 思路 2:代码
4982

5083
```python
84+
class Solution:
85+
def heightChecker(self, heights: List[int]) -> int:
86+
# 待排序数组中最大值元素 heights_max = 100 和最小值元素 heights_min = 1
87+
heights_min, heights_max = 1, 100
88+
# 定义计数数组 counts,大小为 最大值元素 - 最小值元素 + 1
89+
size = heights_max - heights_min + 1
90+
counts = [0 for _ in range(size)]
91+
92+
# 统计值为 height 的元素出现的次数
93+
for height in heights:
94+
counts[height - heights_min] += 1
95+
96+
ans = 0
97+
idx = 0
98+
# 从小到大遍历 counts 的元素值范围
99+
for height in range(heights_min, heights_max + 1):
100+
while counts[height - heights_min]:
101+
# 对于每个元素值,判断是否与对应位置上的 heights[idx] 相等
102+
if heights[idx] != height:
103+
ans += 1
104+
idx += 1
105+
counts[height - heights_min] -= 1
106+
107+
return ans
51108
```
52109

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

55-
- **时间复杂度**
56-
- **空间复杂度**
112+
- **时间复杂度**$O(n + k)$,其中 $n$ 为数组 $heights$ 的长度,$k$ 为数组 $heights$ 的值域范围。
113+
- **空间复杂度**$O(k)$。
57114

Solutions/1151. 最少交换次数来组合所有的 1.md

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,56 @@
99

1010
## 题目大意
1111

12-
给定一个二进制数组 `data`
12+
**描述**给定一个二进制数组 $data$
1313

14-
要求:通过交换位置,将数组中任何位置上的 `1` 组合到一起,并返回所有可能中所需的最少交换次数。
14+
**要求**:通过交换位置,将数组中任何位置上的 $1$ 组合到一起,并返回所有可能中所需的最少交换次数。c
15+
16+
**说明**
17+
18+
- $1 \le data.length \le 10^5$。
19+
- $data[i] == 0 \text{ or } 1$。
20+
21+
**示例**
22+
23+
- 示例 1:
24+
25+
```python
26+
输入: data = [1,0,1,0,1]
27+
输出: 1
28+
解释:
29+
有三种可能的方法可以把所有的 1 组合在一起:
30+
[1,1,1,0,0],交换 1 次;
31+
[0,1,1,1,0],交换 2 次;
32+
[0,0,1,1,1],交换 1 次。
33+
所以最少的交换次数为 1
34+
```
35+
36+
- 示例 2:
37+
38+
```python
39+
输入:data = [0,0,0,1,0]
40+
输出:0
41+
解释:
42+
由于数组中只有一个 1,所以不需要交换。
43+
```
1544

1645
## 解题思路
1746

18-
将数组中任何位置上的 `1` 组合到一起,并要求最少的交换次数。也就是说交换之后,某个连续子数组中全是 `1`,数组其他位置全是 `0`。为此,我们可以维护一个固定长度为 `1` 的个数的滑动窗口,找到滑动窗口中 `0` 最少的个数,这样最终交换出去的 `0` 最少,交换次数也最少。
47+
### 思路 1:滑动窗口
1948

20-
求最少交换次数,也就是求滑动窗口中最少的 `0` 的个数。具体做法如下:
49+
将数组中任何位置上的 $1$ 组合到一起,并要求最少的交换次数。也就是说交换之后,某个连续子数组中全是 $1$,数组其他位置全是 $0$。为此,我们可以维护一个固定长度为 $1$ 的个数的滑动窗口,找到滑动窗口中 $0$ 最少的个数,这样最终交换出去的 $0$ 最少,交换次数也最少。
2150

22-
1. 统计 `1` 的个数,并设置为窗口长度 `window_size`。使用 `window_count` 维护窗口中 `0` 的个数。使用 `ans` 维护窗口中最少的 `0` 的个数,也可以叫做最少交换次数。
23-
2. 如果 `window_size``0`,则说明不用交换,直接返回 `0`
24-
3. 使用两个指针 `left``right``left``right` 都指向数组的第一个元素,即:`left = 0``right = 0`
25-
4. 如果 `data[right] == 0`,则更新窗口中 `0` 的个数,即 `window_count += 1`。然后向右移动 `right`
26-
5. 当窗口元素个数为 `window_size` 时,即:`right - left + 1 >= window_size` 时,更新窗口中最少的 `0` 的个数。
27-
6. 然后如果左侧 `data[left] == 0`,则更新窗口中 `0` 的个数,即 `window_count -= 1`。然后向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `window_size`
28-
7. 重复 4 ~ 6 步,直到 `right` 到达数组末尾。返回答案 `ans`
51+
求最少交换次数,也就是求滑动窗口中最少的 $0$ 的个数。具体做法如下:
2952

30-
## 代码
53+
1. 统计 $1$ 的个数,并设置为窗口长度 $window\underline{}size$。使用 $window\underline{}count$ 维护窗口中 $0$ 的个数。使用 $ans$ 维护窗口中最少的 $0$ 的个数,也可以叫做最少交换次数。
54+
2. 如果 $window\underline{}size$ 为 $0$,则说明不用交换,直接返回 $0$。
55+
3. 使用两个指针 $left$、$right$。$left$、$right$ 都指向数组的第一个元素,即:`left = 0``right = 0`
56+
4. 如果 $data[right] == 0$,则更新窗口中 $0$ 的个数,即 `window_count += 1`。然后向右移动 $right$。
57+
5. 当窗口元素个数为 $window\underline{}size$ 时,即:$right - left + 1 \ge window\underline{}size$ 时,更新窗口中最少的 $0$ 的个数。
58+
6. 然后如果左侧 $data[left] == 0$,则更新窗口中 $0$ 的个数,即 `window_count -= 1`。然后向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 $window\underline{}size$。
59+
7. 重复 4 ~ 6 步,直到 $right$ 到达数组末尾。返回答案 $ans$。
60+
61+
### 思路 1:代码
3162

3263
```python
3364
class Solution:
@@ -55,3 +86,8 @@ class Solution:
5586
return ans if ans != float('inf') else 0
5687
```
5788

89+
### 思路 1:复杂度分析
90+
91+
- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $data$ 的长度。
92+
- **空间复杂度**:$O(1)$。
93+

Solutions/1176. 健身计划评估.md

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,56 @@
99

1010
## 题目大意
1111

12-
好友给自己制定了一份健身计划。想请你帮他评估一下这份计划是否合理。
12+
**描述**好友给自己制定了一份健身计划。想请你帮他评估一下这份计划是否合理。
1313

14-
给定一个数组 `calories`,其中 `calories[i]` 代表好友第 `i` 天需要消耗的卡路里总量。再给定 `lower` 代表较低消耗的卡路里,`upper` 代表较高消耗的卡路里。再给定一个整数 `k`,代表连续 `k` 天。
14+
给定一个数组 $calories$,其中 $calories[i]$ 代表好友第 $i$ 天需要消耗的卡路里总量。再给定 $lower$ 代表较低消耗的卡路里,$upper$ 代表较高消耗的卡路里。再给定一个整数 $k$,代表连续 $k$ 天。
1515

16-
- 如果你的好友在这一天以及之后连续 `k` 天内消耗的总卡路里 `T` 小于 `lower`,则这一天的计划相对糟糕,并失去 `1` 分。
17-
- 如果你的好友在这一天以及之后连续 `k` 天内消耗的总卡路里 `T` 高于 `upper`,则这一天的计划相对优秀,并得到 `1` 分。
18-
- 如果你的好友在这一天以及之后连续 `k` 天内消耗的总卡路里 `T` 大于等于 `lower`,并且小于等于 `upper`,则这份计划普普通通,分值不做变动。
16+
- 如果你的好友在这一天以及之后连续 $k$ 天内消耗的总卡路里 $T$ 小于 $lower$,则这一天的计划相对糟糕,并失去 $1$ 分。
17+
- 如果你的好友在这一天以及之后连续 $k$ 天内消耗的总卡路里 $T$ 高于 $upper$,则这一天的计划相对优秀,并得到 $1$ 分。
18+
- 如果你的好友在这一天以及之后连续 $k$ 天内消耗的总卡路里 $T$ 大于等于 $lower$,并且小于等于 $upper$,则这份计划普普通通,分值不做变动。
1919

20-
输出最后评估的得分情况。
20+
**要求**:输出最后评估的得分情况。
21+
22+
**说明**
23+
24+
- $1 \le k \le calories.length \le 10^5$。
25+
- $0 \le calories[i] \le 20000$。
26+
- $0 \le lower \le upper$。
27+
28+
**示例**
29+
30+
- 示例 1:
31+
32+
```python
33+
输入:calories = [1,2,3,4,5], k = 1, lower = 3, upper = 3
34+
输出:0
35+
解释:calories[0], calories[1] < lower 而 calories[3], calories[4] > upper, 总分 = 0.
36+
```
37+
38+
- 示例 2:
39+
40+
```python
41+
输入:calories = [3,2], k = 2, lower = 0, upper = 1
42+
输出:1
43+
解释:calories[0] + calories[1] > upper, 总分 = 1.
44+
```
2145

2246
## 解题思路
2347

24-
固定长度为 `k` 的滑动窗口题目。具体做法如下:
48+
### 思路 1:滑动窗口
2549

26-
1. `score` 用来维护得分情况,初始值为 `0``window_sum` 用来维护窗口中卡路里总量。
27-
2. `left``right` 都指向数组的第一个元素,即:`left = 0``right = 0`
28-
3. 向右移动 `right`,先将 `k` 个元素填入窗口中。
29-
4. 当窗口元素个数为 `k` 时,即:`right - left + 1 >= k` 时,计算窗口内的卡路里总量,并判断和 `upper``lower` 的关系。同时维护得分情况。
30-
5. 然后向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `k`
31-
6. 重复 4 ~ 5 步,直到 `right` 到达数组末尾。
50+
固定长度为 $k$ 的滑动窗口题目。具体做法如下:
3251

33-
最后输出得分情况 `score`
52+
1. $score$ 用来维护得分情况,初始值为 $0$。$window\underline{}sum$ 用来维护窗口中卡路里总量。
53+
2. $left$ 、$right$ 都指向数组的第一个元素,即:`left = 0``right = 0`
54+
3. 向右移动 $right$,先将 $k$ 个元素填入窗口中。
55+
4. 当窗口元素个数为 $k$ 时,即:$right - left + 1 \ge k$ 时,计算窗口内的卡路里总量,并判断和 $upper$、$lower$ 的关系。同时维护得分情况。
56+
5. 然后向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 $k$。
57+
6. 重复 $4 \sim 5$ 步,直到 $right$ 到达数组末尾。
3458

35-
## 代码
59+
最后输出得分情况 $score$。
60+
61+
### 思路 1:代码
3662

3763
```python
3864
class Solution:
@@ -55,3 +81,8 @@ class Solution:
5581
return score
5682
```
5783

84+
### 思路 1:复杂度分析
85+
86+
- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $calories$ 的长度。
87+
- **空间复杂度**:$O(1)$。
88+

0 commit comments

Comments
 (0)