Skip to content

Commit 778732a

Browse files
committed
修改文章
1 parent a45ea87 commit 778732a

17 files changed

+162
-146
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,17 @@
4141
|[leetcode 647.回文子串](./leetcode%20blind75/字符串/LeetCode%200647.%20回文子串.md)| ✔ | ✔ | ✔ | [回文子串](https://www.bilibili.com/video/BV1Bs421w7iw/) |
4242
|[leetcode 19.删除链表的倒数第N个结点](./leetcode%20blind75/链表/LeetCode%200019.%20删除链表的倒数第%20N%20个结点.md)| ✔ | ✔ | ✔ | [删除链表的倒数第N个结点](https://www.bilibili.com/video/BV1hs421M7Ke/) |
4343
|[leetcode 21.合并两个有序链表](./leetcode%20blind75/链表/LeetCode%200021.%20%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [合并两个有序链表](https://www.bilibili.com/video/BV17w4m1Y7CJ/) |
44-
|[leetcode 23.合并 K 个升序链表](./leetcode%20blind75/链表/LeetCode%200023.%20%E5%90%88%E5%B9%B6%20K%20%E4%B8%AA%E5%8D%87%E5%BA%8F%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [合并 K 个升序链表](https://www.bilibili.com/video/BV136421f7hR/)] |
44+
|[leetcode 23.合并 K 个升序链表](./leetcode%20blind75/链表/LeetCode%200023.%20%E5%90%88%E5%B9%B6%20K%20%E4%B8%AA%E5%8D%87%E5%BA%8F%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [合并 K 个升序链表](https://www.bilibili.com/video/BV136421f7hR/) |
4545
|[leetcode 141.环形链表](./leetcode%20blind75/链表/LeetCode%200141.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [环形链表](https://www.bilibili.com/video/BV18z421q78k/) |
4646
|[leetcode 143.重排链表](./leetcode%20blind75/链表/LeetCode%200143.%20%E9%87%8D%E6%8E%92%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [重排链表](https://www.bilibili.com/video/BV1tx4y1t7YB/) |
4747
|[leetcode 206.反转链表](./leetcode%20blind75/链表/LeetCode%200206.%20%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.md)| ✔ | ✔ | ✔ | [反转链表](https://www.bilibili.com/video/BV1gE421N7W2/) |
48-
|[leetcode 190.颠倒二进制位](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200190.%E9%A2%A0%E5%80%92%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%BD%8D.md)| ✔ | ✘ | ✘ | 录制中 |
48+
|[leetcode 190.颠倒二进制位](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200190.%E9%A2%A0%E5%80%92%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%BD%8D.md)| ✔ | ✔ | ✔ | [颠倒二进制位](https://www.bilibili.com/video/BV1W2421Z7bi/) |
49+
|[leetcode 191.位1的个数](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200191.位1的个数.md)| ✔ | ✔ | ✔ | [位1的个数](https://www.bilibili.com/video/BV1ir421M7XU/) |
50+
|[leetcode 268.丢失的数字](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200268.丢失的数字.md)| ✔ | ✔ | ✔ | [丢失的数字](https://www.bilibili.com/video/BV1HS42197Hc/) |
51+
|[leetcode 338.比特位计数](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200338.%20比特位计数.md)| ✔ | ✔ | ✔ | [比特位计数](https://www.bilibili.com/video/BV1RE421w7C7/) |
52+
|[leetcode 371.两整数之和](./leetcode%20blind75/%E4%BD%8D%E8%BF%90%E7%AE%97/LeetCode%200371.两整数之和.md)| ✔ | ✔ | ✔ | [两整数之和](https://www.bilibili.com/video/BV1RZ421K7YF/) |
53+
|[leetcode 39.组合总数](./leetcode%20blind75/动态规划/LeetCode%200039.%20组合总和.md)| ✔ | ✘ | ✘ | 录制中 |
54+
4955

5056
所有的文章都是我利用工作之余的时间写的,尽可能使用最简洁易懂的方式,由浅入深,还画了一些帮助理解的图片。每写完一篇我都会以小白的姿态去反复阅读,反复修改。 也获得了一些同学的认可,还有一些同学在力扣的题解评论区给我提建议,我也会根据同学们的建议去不断调整。我始终认为个人的思路是有局限性的,因为每个人对基础知识的掌握程度是不一样的,一个人认为理所当然的结论,另一个人可能想破脑袋都不理解,所以需要我们共同去不断完善。非常欢迎大家通过力扣评论、公众号「编程网事」后台给我提建议,或者直接提给我你的合并请求。
5157

leetcode blind75/位运算/LeetCode 0190.颠倒二进制位.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
> *题目链接:* https://leetcode.cn/problems/reverse-bits/
3+
>
4+
>*视频题解:* https://www.bilibili.com/video/BV1W2421Z7bi/
35
46
# LeetCode 190.颠倒二进制位
57

leetcode blind75/位运算/LeetCode 0191.位1的个数.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
> *题目链接:* https://leetcode.cn/problems/number-of-1-bits/
3+
>
4+
>*视频题解:* https://www.bilibili.com/video/BV1ir421M7XU/
35
46
# LeetCode 191.位1的个数
57

leetcode blind75/位运算/LeetCode 0268.丢失的数字.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
> *题目链接:* https://leetcode.cn/problems/missing-number/
3+
>
4+
>*视频题解:* https://www.bilibili.com/video/BV1HS42197Hc/
35
46
# LeetCode 268.丢失的数字
57

@@ -84,6 +86,7 @@ class Solution:
8486
```
8587
0 + 1 +...+ n = nums[0] + nums[1] +...+ nums[n-1] + X
8688
```
89+
8790
我们只需要用区间`[0, n]`所有元素的和减去`nums`中所有元素的和就得到最终的结果`X`
8891

8992
### C++代码
@@ -136,6 +139,4 @@ class Solution:
136139

137140
**时间复杂度:** 两种方法的整个过程都是只遍历了一遍数组,所以时间复杂度为*O(n)*`n`为数组`nums`的长度。
138141

139-
**空间复杂度:** 两种方法都只使用了几个整型变量,所以空间复杂度都是*O(1)*
140-
141-
142+
**空间复杂度:** 两种方法都只使用了几个整型变量,所以空间复杂度都是*O(1)*

leetcode blind75/位运算/LeetCode 0338. 比特位计数.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
> *题目链接:* https://leetcode.cn/problems/counting-bits/
3+
>
4+
>*视频题解:* https://www.bilibili.com/video/BV1RE421w7C7/
35
46
# LeetCode 338. 比特位计数
57

@@ -189,5 +191,3 @@ class Solution:
189191
**时间复杂度:** 两种方法都是*O(n)*,因为只遍历一遍区间`[0, n]`
190192

191193
**空间复杂度:** 两种方法都是*O(n)*,只用到一个长度为`n+1`的数组`dp`
192-
193-

leetcode blind75/位运算/LeetCode 0371.两整数之和.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
> *题目链接:* https://leetcode.cn/problems/sum-of-two-integers/
3+
>
4+
>*视频题解:* https://www.bilibili.com/video/BV1RZ421K7YF/
35
46
# LeetCode 371.两整数之和
57

leetcode blind75/动态规划/LeetCode 0055. 跳跃游戏.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
输出:true
1919
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
2020
```
21+
2122
## 知识回顾
2223

2324
**贪心算法**是一种常见的算法思想,它通常用于解决优化问题。贪心算法的基本思想是,在每一步选择中都采取当前状态下最优的选择,从而希望最终得到全局最优解。
@@ -27,6 +28,7 @@
2728
本题是一道贪心算法应用的经典问题。应用贪心算法的关键就是**每一步都采取当前状态下的最优选择**
2829

2930
本题的算法如下:
31+
3032
1. 逆序遍历`nums``target=nums.size()`
3133
2. 遍历到索引`i`,跳`nums[i]`步,`i + nums[i] >= target`说明子目标可达,此时更新`target = i`
3234
3. 最终`target == 0`说明总目标可达。
@@ -56,10 +58,9 @@ public:
5658
}
5759
};
5860
```
61+
5962
## 复杂度分析
6063

6164
**时间复杂度:** *O(n)*`n``nums`的长度。
6265

6366
**空间复杂度:** *O(1)*
64-
65-

leetcode blind75/动态规划/LeetCode 0062. 不同路径.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
```
2222
## 知识回顾
2323

24-
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解**自下而上**推导出原问题的最优解
24+
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解推导出原问题的最优解。可以通过两点来判断一个问题能不能通过动态规划来解,一是该问题是否存在递归结构,二是对应的子问题能否记忆化。动态规划可以通过**带备忘录的自上而下的递归****自下而上的迭代**来分别实现。由于递归需要用到栈来实现,一些语言对递归的深度是有限制的,所以**自下而上的迭代是动态规划的最佳实现方式**
2525

2626
## 思路解析
2727

28+
通过分析该问题存在递归结构,并且存在大量子问题可以记忆化保存,所以可以通过动态规划来实现。
29+
2830
本题是经典的二维动态规划问题,需要找到解决动态规划问题的两个突破点:**推导出状态转移公式****边界条件处理**
2931

3032
首先定义`dp[i][j]`为机器人从左上角走到坐标为`(i,j)`的网格所有的路径数目,`i`为行,`j`为列。
@@ -70,6 +72,3 @@ public:
7072
**时间复杂度:** *O(mn)*,遍历完`m x n`的网格。
7173

7274
**空间复杂度:** *O(mn)*,即`dp`数组的大小。
73-
74-
75-

leetcode blind75/动态规划/LeetCode 0070.爬楼梯.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,22 @@
2020

2121
## 知识回顾
2222

23-
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解**自下而上**推导出原问题的最优解
23+
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解推导出原问题的最优解。可以通过两点来判断一个问题能不能通过动态规划来解,一是该问题是否存在递归结构,二是对应的子问题能否记忆化。动态规划可以通过**带备忘录的自上而下的递归****自下而上的迭代**来分别实现。由于递归需要用到栈来实现,一些语言对递归的深度是有限制的,所以**自下而上的迭代是动态规划的最佳实现方式**
2424

2525
## 思路解析
2626

27-
本题可以用**动态规划**来解,**动态规划**的两个核心点是**推导状态转移公式****边界处理**
28-
29-
**下面我们先来推导状态转移公式**,假设只有`4`个台阶,`0`阶代表地面。
27+
假设只有`4`个台阶,`0`阶代表地面。
3028

3129
![](https://gitee.com/ldtech007/picture/raw/master/pic/lc-0070-01.png)
3230

33-
整个爬楼梯的过程可以表示成下图
31+
整个爬楼梯的过程对应的决策树可以表示成下图
3432

3533
![](https://gitee.com/ldtech007/picture/raw/master/pic/lc-0070-02.png)
3634

3735
**每个节点的值表示剩余的台阶数**,从根节点到叶子结点组成的路径代表一种爬楼梯的方法。
3836

37+
整个决策树存在递归结构,还存在重复子问题`两个节点2``三个节点1`,这些子问题计算一次后可以直接保存下来,避免多次重复计算。这就满足了使用动态规划的条件:**存在递归结构****子问题可以记忆化**。所以本题可以用**动态规划**来解,**动态规划**的两个核心点是**推导状态转移公式****边界处理**
38+
3939
**定义`dp[i]``i`个台阶对应的爬楼梯的方法个数**`dp[i]`的准确定义是推导状态转移公式的关键。
4040

4141
因为每次只能爬`1``2`个台阶,从上面的图可以看出`4`个台阶的爬楼梯方法可以拆解成`3``2`个台阶爬楼梯方法之和。说白了就是`节点4`到叶子`节点0`的所有路径等于`节点3``节点2`到叶子节点路径的总和。

leetcode blind75/动态规划/LeetCode 0091. 解码方法.md

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,74 @@
3434

3535
## 知识回顾
3636

37-
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解来推导出原问题的最优解
37+
**动态规划**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于**求解最优化问题**,例如最长公共子序列、背包问题等。动态规划的核心思想是将原问题分解为若干个子问题,通过求解子问题的最优解推导出原问题的最优解。可以通过两点来判断一个问题能不能通过动态规划来解,一是该问题是否存在递归结构,二是对应的子问题能否记忆化。动态规划可以通过**带备忘录的自上而下的递归****自下而上的迭代**来分别实现。由于递归需要用到栈来实现,一些语言对递归的深度是有限制的,所以**自下而上的迭代是动态规划的最佳实现方式**
3838

39-
**回溯**是一种通过将原问题分解为子问题来求解复杂问题的算法思想。它通常用于求解组合问题、排列问题等。回溯的核心思想是**通过递归的方式枚举所有可能的解**,直到找到符合条件的解为止。回溯算法通常使用递归函数来实现,每次递归时都会对当前状态进行判断,如果符合条件则继续递归,否则回溯到上一层状态。
39+
## 思路解析
4040

41-
动态规划和回溯的相似之处在于它们都将原问题分解为子问题来求解,但它们的不同之处在于动态规划通常用于**自下而上**求解最优化问题,而回溯通常用于**自上而下**求解所有可能的解。
41+
计算`s``[i,n)`区间解码数量时,可以把问题拆解成**独立的子问题**
42+
43+
1. 如果`s[i]``'1'~'9'`范围内,可以被单独解码,这个时候被解码的数量其实就是子问题`[i+1,n)`区间解码数量。
44+
2. 如果`s[i]s[i+1]``"10"~"26"`范围内,可以被组合解码,这个时候被解码的数量其实就是子问题`[i+2,n)`区间解码数量。
45+
3. 如果`1``2`中的条件都满足,那么被解码的数量就是子问题`[i+1,n)`区间和子问题`[i+2,n)`区间解码数量之和。
46+
47+
上述过程的子问题是可以记忆化的,我们增加一个**备忘录**来保存子问题的解,推导原问题时避免重复计算。这就满足了使用动态规划的条件:**存在递归结构****子问题可以记忆化**。所以本题可以用**动态规划**来解。动态规划可以通过**带备忘录的自上而下的递归****自下而上的迭代**来分别实现。
48+
49+
### 方法1 自上而下的递归+备忘录
50+
51+
递归的关键在于**划分子问题****确定跳出递归的条件**
52+
53+
递归是一种**自上而下**的推导方式,这里**跳出递归条件**就是**子问题区间为空****备忘录中已经保存了子问题的解**
54+
55+
### C++代码
56+
57+
```cpp
58+
class Solution {
59+
public:
60+
int numDecodings(string s) {
61+
map<int, int> count;
62+
count[s.length()] = 1;
63+
return dfs(s, count, 0);
64+
}
65+
66+
int dfs(string& s, map<int, int>& count, int i) {
67+
//跳出递归条件
68+
if (count.find(i) != count.end()) {
69+
return count[i];
70+
}
71+
//跳出递归条件
72+
if (s[i] == '0') {
73+
return 0;
74+
}
75+
//子问题处理
76+
int res = dfs(s, count, i + 1);
77+
if (i + 1 < s.length() && (s[i] == '1' || (s[i] == '2'&& s[i + 1] >= '0' && s[i + 1] <= '6'))) {
78+
//子问题处理
79+
res += dfs(s, count, i + 2);
80+
}
81+
//更新备忘录
82+
count[i] = res;
83+
return res;
84+
}
85+
};
86+
```
87+
88+
### 复杂度分析
89+
90+
**时间复杂度:** *O(n)*`n``s`的长度。
91+
92+
**空间复杂度:** *O(n)*`n``s`的长度。
4293

43-
## 思路解析
4494

45-
### 方法1 动态规划
95+
### 方法2 自下而上的迭代
96+
97+
实现**自下而上**迭代的两个关键步骤:**状态转移公式推导****边界情况处理**
4698

47-
我们先介绍动态规划的解法,动态规划的两个关键步骤:**状态转移公式推导****边界情况处理**
4899
首先定义`dp[i]``s``i`字符,即区间`[0,i)`上解码方法的总数。
49100

50-
动态规划是一种**自下而上**的推导方式,在我们求`dp[i]`时,其实子问题`dp[i-1]``dp[i-2]`已经被推导出来了。
101+
由于迭代是**自下而上**,在我们求`dp[i]`时,其实子问题`dp[i-1]``dp[i-2]`已经被推导出来了。
51102

52103
因为一个字符被编码后其范围在`"1"~"26"`之间,我们需要对`s[i-1]``s[i-2]`分情况进行分析。
104+
53105
1. `s[i-1]`被单独解码,如果`s[i-1]``'1'~'9'`范围内,可以被单独解码,这个时候被解码的数量`dp[i]`等于`dp[i-1]`
54106
2. `s[i-2]s[i-1]`一起被解码,如果`s[i-2]s[i-1]``"10"~"26"`范围内,可以被组合解码,这个时候被解码的数量`dp[i]`等于`dp[i-2]`
55107
3. 如果`1``2`中的条件都满足,那么被解码的数量`dp[i]`等于`dp[i-1] + dp[i-2]`
@@ -83,60 +135,10 @@ public:
83135

84136
};
85137
```
86-
### 复杂度分析
87-
88-
**时间复杂度:** *O(n)*,`n`为`s`的长度。
89-
90-
**空间复杂度:** *O(n)*,`n`为`s`的长度。
91-
92-
### 方法2 回溯+备忘录
93-
94-
回溯的关键在于**划分子问题**和**确定回溯条件**。
95-
96-
回溯是一种**自上而下**的推导方式,在我们要求`s`的`[i,n)`区间解码数量时,需要把问题拆解成**独立的子问题**:
97-
1. 如果`s[i]`在`'1'~'9'`范围内,可以被单独解码,这个时候被解码的数量其实就是子问题`[i+1,n)`区间解码数量。
98-
2. 如果`s[i]s[i+1]`在`"10"~"26"`范围内,可以被组合解码,这个时候被解码的数量其实就是子问题`[i+2,n)`区间解码数量。
99-
3. 如果`1`和`2`中的条件都满足,那么被解码的数量就是子问题`[i+1,n)`区间和子问题`[i+2,n)`区间解码数量之和。
100-
101-
对于上述过程我们增加一个**备忘录**来保存子问题的解,可以避免多次去计算同一个子问题的解,提高效率。
102-
103-
**回溯条件**就是**子问题区间为空**或**备忘录中已经保存了子问题的解**。
104-
105-
### C++代码
106-
107-
```cpp
108-
class Solution {
109-
public:
110-
int numDecodings(string s) {
111-
map<int, int> count;
112-
count[s.length()] = 1;
113-
return dfs(s, count, 0);
114-
}
115-
116-
int dfs(string& s, map<int, int>& count, int i) {
117-
//回溯条件
118-
if (count.find(i) != count.end()) {
119-
return count[i];
120-
}
121-
//回溯条件
122-
if (s[i] == '0') {
123-
return 0;
124-
}
125-
//子问题处理
126-
int res = dfs(s, count, i + 1);
127-
if (i + 1 < s.length() && (s[i] == '1' || (s[i] == '2'&& s[i + 1] >= '0' && s[i + 1] <= '6'))) {
128-
//子问题处理
129-
res += dfs(s, count, i + 2);
130-
}
131-
//更新备忘录
132-
count[i] = res;
133-
return res;
134-
}
135-
};
136-
```
137138
138139
### 复杂度分析
139140
140141
**时间复杂度:** *O(n)*,`n`为`s`的长度。
141142
142143
**空间复杂度:** *O(n)*,`n`为`s`的长度。
144+

0 commit comments

Comments
 (0)