Skip to content

Commit c5535e5

Browse files
committed
update: 62.不同路径
1 parent 5c52e99 commit c5535e5

File tree

5 files changed

+159
-243
lines changed

5 files changed

+159
-243
lines changed

README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,22 @@
162162

163163
### 高频面试题
164164

165+
**二叉树遍历系列**
166+
165167
- [x] [【day-34】二叉树遍历系列](./medium/hot/34.traversal-of-binary-tree.md)
166-
- [x] [【day-34】581.最短无序连续子数组](./medium/day-34.md)
167-
- [x] [【day-35】78.子集](./medium/day-35.md)
168-
- [x] [【day-36】62.不同路径](./medium/day-36.md)
168+
169+
**位运算系列**
170+
171+
- [ ] [【day-36】78.子集](./medium/hot/36.subsets.md)
172+
173+
**动态规划系列**
174+
175+
- [x] [【day-37】62.不同路径](./medium/hot/37.unique-paths.md)
176+
169177
- [x] [【day-37】有效括号系列](./medium/day-37.md)
170178
- [x] [【day-38】反转链表系列](./medium/day-38.md)
171179
- [x] [【day-39】前缀和系列](./medium/day-39.md)
180+
- [x] [581.最短无序连续子数组](./medium/day-34.md)
172181

173182
### 前缀树
174183

basic/array-stack-queue/02.shortest-distance-to-a-character.md

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ https://leetcode-cn.com/problems/shortest-distance-to-a-character
1212
- [思路](#思路-1)
1313
- [复杂度分析](#复杂度分析-1)
1414
- [代码](#代码-1)
15-
- [解法 3:水波法](#解法-3水波法)
15+
- [解法 3:贪心](#解法-3贪心)
1616
- [思路](#思路-2)
1717
- [复杂度分析](#复杂度分析-2)
1818
- [代码](#代码-2)
@@ -45,9 +45,13 @@ S 和 C 中的所有字母均为小写字母。
4545

4646
### 思路
4747

48-
直觉想法,就是对每个字符进行分别处理:从当前下标出发,分别向左、右两个方向去寻找目标字符 `C`
48+
这是最符合直觉的思路,对每个字符分别进行如下处理:
4949

50-
![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/821_0.png)
50+
- 从当前下标出发,分别向左、右两个方向去寻找目标字符 `C`
51+
- 只在一个方向找到的话,直接计算字符距离。
52+
- 两个方向都找到的话,取两个距离的最小值。
53+
54+
![](https://pic.leetcode-cn.com/1606962060-CnDiHj-file_1606962060610)
5155

5256
### 复杂度分析
5357

@@ -103,9 +107,11 @@ var shortestToChar = function (S, C) {
103107

104108
### 思路
105109

106-
因为目标字符 `C``S` 中的位置是不变的,所以我们可以将 `C` 的所有下标记录在一个数组 `cIndices` 中。
110+
空间换时间是编程中很常见的一种 trade-off (反过来,时间换空间也是)。
111+
112+
因为目标字符 `C``S` 中的位置是不变的,所以我们可以提前将 `C` 的所有下标记录在一个数组 `cIndices` 中。
107113

108-
然后对于字符串 `S` 中的每个字符, `cIndices` 中找到距离当前位置最近的下标,记录到结果数组中
114+
然后遍历字符串 `S` 中的每个字符, `cIndices` 中找到距离当前位置最近的下标,计算距离
109115

110116
### 复杂度分析
111117

@@ -154,28 +160,28 @@ var shortestToChar = function (S, C) {
154160
};
155161
```
156162

157-
## 解法 3:水波法
163+
## 解法 3:贪心
158164

159165
### 思路
160166

161-
其实对于每个字符来说,它只关心离它最近的那个 `C` 字符,所以我们可以用类似前缀和的思想
167+
其实对于每个字符来说,它只关心离它最近的那个 `C` 字符,其他的它都不管。所以这里还可以用贪心的思路
162168

163169
1.`从左往右` 遍历字符串 `S`,用一个数组 left 记录每个字符 `左侧` 出现的最后一个 `C` 字符的下标;
164-
2. `从右往左` 遍历字符串 `S`,用一个数组 right 记录每个字符 `右侧` 出现的最后一个 `C` 字符的下标;
165-
3. 然后同时遍历这两个数组,计算距离最小值放进结果数组中
170+
2. `从右往左` 遍历字符串 `S`,用一个数组 right 记录每个字符 `右侧` 出现的最后一个 `C` 字符的下标;
171+
3. 然后同时遍历这两个数组,计算距离最小值
166172

167173
**优化 1**
168174

169-
再多想一步,其实第二个数组也并不需要。因为对于左右两侧的 `C` 字符,我们也只关心距离最近的那一个,所以第二次遍历的时候可以看情况覆盖掉 left 数组的值
175+
再多想一步,其实第二个数组并不需要。因为对于左右两侧的 `C` 字符,我们也只关心其中距离更近的那一个,所以第二次遍历的时候可以看情况覆盖掉第一个数组的值
170176

171177
1. 字符左侧没有出现过 `C` 字符
172178
2. `i - left` > `right - i` (i 为当前字符下标,left 为字符左侧最近的 `C` 下标,right 为字符右侧最近的 `C` 下标)
173179

174-
如果出现以上两种情况,就可以用原本 right 数组中的值覆盖掉 left 数组中的值。最后我们再遍历一次数组计算距离
180+
如果出现以上两种情况,就可以进行覆盖,最后再遍历一次数组计算距离
175181

176182
**优化 2**
177183

178-
如果我们是直接记录距离,而不是记录 `C` 的下标,还可以省掉最后一次遍历计算距离的过程。
184+
如果我们是直接记录 `C` 与当前字符的距离,而不是记录 `C` 的下标,还可以省掉最后一次遍历计算距离的过程。
179185

180186
### 复杂度分析
181187

@@ -252,9 +258,9 @@ var shortestToChar = function (S, C) {
252258

253259
### 思路
254260

255-
`C``S` 划分成一个个窗口,对于窗口中的每个字符,分别计算它们到窗口左右两边的距离,取最小值即可
261+
`C` 看成分界线,`S` 划分成一个个窗口。然后对每个窗口进行遍历,分别计算每个字符到窗口边界的距离最小值
256262

257-
![](https://cdn.jsdelivr.net/gh/suukii/91-days-algorithm/assets/821_1.png)
263+
![](https://pic.leetcode-cn.com/1606962060-WhqxbZ-file_1606962060746)
258264

259265
### 复杂度分析
260266

medium/day-35.md

Lines changed: 0 additions & 207 deletions
This file was deleted.

medium/hot/36.subsets.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# 78.子集
2+
3+
https://leetcode-cn.com/problems/subsets
4+
5+
## 题目描述
6+
7+
```
8+
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
9+
10+
说明:解集不能包含重复的子集。
11+
12+
示例:
13+
14+
输入: nums = [1,2,3]
15+
输出:
16+
[
17+
[3],
18+
[1],
19+
[2],
20+
[1,2,3],
21+
[1,3],
22+
[2,3],
23+
[1,2],
24+
[]
25+
]
26+
27+
来源:力扣(LeetCode)
28+
链接:https://leetcode-cn.com/problems/subsets
29+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
30+
```
31+
32+
## 方法 1:回溯
33+
34+
### 思路
35+
36+
如果我们要生成**一个**子集,那步骤大概是:
37+
38+
- 初始化一个数组用来表示这个子集;
39+
- 遍历数组,对每个元素做出选择:
40+
- 把它放进子集中;
41+
- 不把它放进子集中;
42+
- 遍历结束后就得到了一个子集;
43+
44+
那如果要生成所有的子集的话:
45+
46+
- 当我们对当前元素做出选择后,可以递归地去对数组剩余的其他元素做选择;
47+
- 等递归到数组的最后一个元素,也就是说,我们已经遍历完一轮数组,对每个元素都做出了选择,那我们就得到了一个子集,把这个子集存到一个全局数组变量中;
48+
- 等到 DFS 结束后返回这个全局变量就行;
49+
50+
### 复杂度分析
51+
52+
- 时间复杂度:由排列组合原理可知,一共有 $2^N$ 种组合,因此时间复杂度为 $O(2^N)$,其中 $N$ 为数字的个数。
53+
- 空间复杂度:由于调用栈深度最多为 $N$,且临时数组长度不会超过 $N$,因此空间复杂度为 $O(N)$,其中 $N$ 为数字的个数。
54+
55+
### 代码
56+
57+
TypeScript Code
58+
59+
```ts
60+
function subsets(nums: number[]): number[][] {
61+
const res: number[][] = [];
62+
63+
const dfs = (nums: number[], cur: number, sub: number[]): void => {
64+
if (cur === nums.length) {
65+
res.push(sub);
66+
return;
67+
}
68+
// exclude the current element
69+
dfs(nums, cur + 1, sub);
70+
// include the current element
71+
dfs(nums, cur + 1, [...sub, nums[cur]]);
72+
};
73+
74+
dfs(nums, 0, []);
75+
return res;
76+
}
77+
```

0 commit comments

Comments
 (0)