diff --git a/README.md b/README.md
index 022a45e8..267d794e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定)
+👉 推荐 [Gitee同步](https://gitee.com/programmercarl/leetcode-master)
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
@@ -477,6 +478,11 @@
* [100.相同的树](./problems/0100.相同的树.md) 同101.对称二叉树 一个思路
* [116.填充每个节点的下一个右侧节点指针](./problems/0116.填充每个节点的下一个右侧节点指针.md)
+## 回溯算法
+
+* [52.N皇后II](./problems/0052.N皇后II.md)
+
+
## 贪心
* [649.Dota2参议院](./problems/0649.Dota2参议院.md) 有难度
diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md
index 387e75c3..5404b620 100644
--- a/problems/0051.N皇后.md
+++ b/problems/0051.N皇后.md
@@ -9,7 +9,7 @@
## 第51题. N皇后
-题目链接: https://leetcode-cn.com/problems/n-queens/
+[力扣题目链接](https://leetcode-cn.com/problems/n-queens/)
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
diff --git a/problems/0052.N皇后II.md b/problems/0052.N皇后II.md
new file mode 100644
index 00000000..81f5c7ea
--- /dev/null
+++ b/problems/0052.N皇后II.md
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+
+
+# 52. N皇后II
+
+题目链接:https://leetcode-cn.com/problems/n-queens-ii/
+
+n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
+
+上图为 8 皇后问题的一种解法。
+
+
+给定一个整数 n,返回 n 皇后不同的解决方案的数量。
+
+示例:
+
+输入: 4
+输出: 2
+解释: 4 皇后问题存在如下两个不同的解法。
+[
+ [".Q..", // 解法 1
+ "...Q",
+ "Q...",
+ "..Q."],
+
+ ["..Q.", // 解法 2
+ "Q...",
+ "...Q",
+ ".Q.."]
+]
+
+# 思路
+
+
+想看:[51.N皇后](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg) ,基本没有区别
+
+# C++代码
+
+```CPP
+class Solution {
+private:
+int count = 0;
+void backtracking(int n, int row, vector& chessboard) {
+ if (row == n) {
+ count++;
+ return;
+ }
+ for (int col = 0; col < n; col++) {
+ if (isValid(row, col, chessboard, n)) {
+ chessboard[row][col] = 'Q'; // 放置皇后
+ backtracking(n, row + 1, chessboard);
+ chessboard[row][col] = '.'; // 回溯
+ }
+ }
+}
+bool isValid(int row, int col, vector& chessboard, int n) {
+ int count = 0;
+ // 检查列
+ for (int i = 0; i < row; i++) { // 这是一个剪枝
+ if (chessboard[i][col] == 'Q') {
+ return false;
+ }
+ }
+ // 检查 45度角是否有皇后
+ for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {
+ if (chessboard[i][j] == 'Q') {
+ return false;
+ }
+ }
+ // 检查 135度角是否有皇后
+ for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
+ if (chessboard[i][j] == 'Q') {
+ return false;
+ }
+ }
+ return true;
+}
+
+public:
+ int totalNQueens(int n) {
+ std::vector chessboard(n, std::string(n, '.'));
+ backtracking(n, 0, chessboard);
+ return count;
+
+ }
+};
+```
+
+# 其他语言补充
+
diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md
index cba7d6c7..53159978 100644
--- a/problems/0053.最大子序和.md
+++ b/problems/0053.最大子序和.md
@@ -9,7 +9,7 @@
## 53. 最大子序和
-题目地址:https://leetcode-cn.com/problems/maximum-subarray/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-subarray/)
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
diff --git a/problems/0053.最大子序和(动态规划).md b/problems/0053.最大子序和(动态规划).md
index 0932c77f..1efd7e12 100644
--- a/problems/0053.最大子序和(动态规划).md
+++ b/problems/0053.最大子序和(动态规划).md
@@ -8,7 +8,7 @@
## 53. 最大子序和
-题目地址:https://leetcode-cn.com/problems/maximum-subarray/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-subarray/)
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
@@ -19,7 +19,7 @@
## 思路
-这道题之前我们在讲解贪心专题的时候用贪心算法解决过一次,[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)。
+这道题之前我们在讲解贪心专题的时候用贪心算法解决过一次,[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)。
这次我们用动态规划的思路再来分析一次。
@@ -87,7 +87,7 @@ public:
## 总结
-这道题目用贪心也很巧妙,但有一点绕,需要仔细想一想,如果想回顾一下贪心就看这里吧:[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)
+这道题目用贪心也很巧妙,但有一点绕,需要仔细想一想,如果想回顾一下贪心就看这里吧:[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)
动规的解法还是很直接的。
diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md
index 0b1c1d36..c9ebe0fe 100644
--- a/problems/0055.跳跃游戏.md
+++ b/problems/0055.跳跃游戏.md
@@ -9,7 +9,7 @@
## 55. 跳跃游戏
-题目链接:https://leetcode-cn.com/problems/jump-game/
+[力扣题目链接](https://leetcode-cn.com/problems/jump-game/)
给定一个非负整数数组,你最初位于数组的第一个位置。
diff --git a/problems/0056.合并区间.md b/problems/0056.合并区间.md
index 441cc63c..2322951a 100644
--- a/problems/0056.合并区间.md
+++ b/problems/0056.合并区间.md
@@ -9,7 +9,7 @@
## 56. 合并区间
-题目链接:https://leetcode-cn.com/problems/merge-intervals/
+[力扣题目链接](https://leetcode-cn.com/problems/merge-intervals/)
给出一个区间的集合,请合并所有重叠的区间。
@@ -126,7 +126,7 @@ public:
那应该怎么办呢?
-正如我贪心系列开篇词[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中讲解的一样,贪心本来就没有套路,也没有框架,所以各种常规解法需要多接触多练习,自然而然才会想到。
+正如我贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中讲解的一样,贪心本来就没有套路,也没有框架,所以各种常规解法需要多接触多练习,自然而然才会想到。
「代码随想录」会把贪心常见的经典题目覆盖到,大家只要认真学习打卡就可以了。
diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md
index 6df8c83d..7d02ff15 100644
--- a/problems/0059.螺旋矩阵II.md
+++ b/problems/0059.螺旋矩阵II.md
@@ -10,7 +10,7 @@
## 59.螺旋矩阵II
-题目地址:https://leetcode-cn.com/problems/spiral-matrix-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
@@ -33,7 +33,7 @@
结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里哪里有问题,改了那里这里又跑不起来了。
-大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
+大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
而求解本题依然是要坚持循环不变量原则。
diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md
index 84c84075..ce29cca1 100644
--- a/problems/0062.不同路径.md
+++ b/problems/0062.不同路径.md
@@ -8,7 +8,7 @@
## 62.不同路径
-题目链接:https://leetcode-cn.com/problems/unique-paths/
+[力扣题目链接](https://leetcode-cn.com/problems/unique-paths/)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
@@ -40,7 +40,7 @@
示例 4:
输入:m = 3, n = 3
输出:6
-
+
提示:
* 1 <= m, n <= 100
* 题目数据保证答案小于等于 2 * 10^9
diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md
index 3df1b301..c01846bd 100644
--- a/problems/0063.不同路径II.md
+++ b/problems/0063.不同路径II.md
@@ -8,7 +8,7 @@
## 63. 不同路径 II
-题目链接:https://leetcode-cn.com/problems/unique-paths-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
@@ -49,11 +49,11 @@
## 思路
-这道题相对于[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A) 就是有了障碍。
+这道题相对于[62.不同路径](https://programmercarl.com/0062.不同路径.html) 就是有了障碍。
第一次接触这种题目的同学可能会有点懵,这有障碍了,应该怎么算呢?
-[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。
+[62.不同路径](https://programmercarl.com/0062.不同路径.html)中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。
动规五部曲:
@@ -77,7 +77,7 @@ if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i
3. dp数组如何初始化
-在[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)不同路径中我们给出如下的初始化:
+在[62.不同路径](https://programmercarl.com/0062.不同路径.html)不同路径中我们给出如下的初始化:
```
vector> dp(m, vector(n, 0)); // 初始值为0
@@ -159,7 +159,7 @@ public:
## 总结
-本题是[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)的障碍版,整体思路大体一致。
+本题是[62.不同路径](https://programmercarl.com/0062.不同路径.html)的障碍版,整体思路大体一致。
但就算是做过62.不同路径,在做本题也会有感觉遇到障碍无从下手。
diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md
index bb9a757c..4f049e4a 100644
--- a/problems/0070.爬楼梯.md
+++ b/problems/0070.爬楼梯.md
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 70. 爬楼梯
-题目地址:https://leetcode-cn.com/problems/climbing-stairs/
+[力扣题目链接](https://leetcode-cn.com/problems/climbing-stairs/)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
@@ -196,9 +196,9 @@ public:
## 总结
-这道题目和[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)题目基本是一样的,但是会发现本题相比[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)难多了,为什么呢?
+这道题目和[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)题目基本是一样的,但是会发现本题相比[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)难多了,为什么呢?
-关键是 [动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w) 题目描述就已经把动规五部曲里的递归公式和如何初始化都给出来了,剩下几部曲也自然而然的推出来了。
+关键是 [动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html) 题目描述就已经把动规五部曲里的递归公式和如何初始化都给出来了,剩下几部曲也自然而然的推出来了。
而本题,就需要逐个分析了,大家现在应该初步感受出[关于动态规划,你该了解这些!](https://leetcode-cn.com/circle/article/tNuNnM/)里给出的动规五部曲了。
diff --git a/problems/0070.爬楼梯完全背包版本.md b/problems/0070.爬楼梯完全背包版本.md
index f7a80f3b..4410dbaf 100644
--- a/problems/0070.爬楼梯完全背包版本.md
+++ b/problems/0070.爬楼梯完全背包版本.md
@@ -13,7 +13,7 @@
## 70. 爬楼梯
-链接:https://leetcode-cn.com/problems/climbing-stairs/
+[力扣题目链接](https://leetcode-cn.com/problems/climbing-stairs/)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
@@ -38,7 +38,7 @@
## 思路
-这道题目 我们在[动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw) 中已经讲过一次了,原题其实是一道简单动规的题目。
+这道题目 我们在[动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html) 中已经讲过一次了,原题其实是一道简单动规的题目。
既然这么简单为什么还要讲呢,其实本题稍加改动就是一道面试好题。
@@ -52,7 +52,7 @@
**此时大家应该发现这就是一个完全背包问题了!**
-和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)基本就是一道题了。
+和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)基本就是一道题了。
动规五部曲分析如下:
@@ -62,7 +62,7 @@
2. 确定递推公式
-在[动态规划:494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) 、 [动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)、[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)中我们都讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
+在[动态规划:494.目标和](https://programmercarl.com/0494.目标和.html) 、 [动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)、[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)中我们都讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
本题呢,dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]
@@ -84,12 +84,11 @@
5. 举例来推导dp数组
-介于本题和[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)几乎是一样的,这里我就不再重复举例了。
+介于本题和[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)几乎是一样的,这里我就不再重复举例了。
以上分析完毕,C++代码如下:
-
-```cpp
+```
class Solution {
public:
int climbStairs(int n) {
diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md
index 8ec0a65b..2045c1fd 100644
--- a/problems/0072.编辑距离.md
+++ b/problems/0072.编辑距离.md
@@ -8,7 +8,7 @@
## 72. 编辑距离
-https://leetcode-cn.com/problems/edit-distance/
+[力扣题目链接](https://leetcode-cn.com/problems/edit-distance/)
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
@@ -35,7 +35,7 @@ inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
-
+
提示:
diff --git a/problems/0077.组合.md b/problems/0077.组合.md
index d88a5711..01d1a537 100644
--- a/problems/0077.组合.md
+++ b/problems/0077.组合.md
@@ -11,7 +11,7 @@
# 第77题. 组合
-题目链接:https://leetcode-cn.com/problems/combinations/
+[力扣题目链接](https://leetcode-cn.com/problems/combinations/ )
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
@@ -80,7 +80,7 @@ for (int i = 1; i <= n; i++) {
如果脑洞模拟回溯搜索的过程,绝对可以让人窒息,所以需要抽象图形结构来进一步理解。
-**我们在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。
+**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。
那么我把组合问题抽象为如下树形结构:
@@ -100,7 +100,7 @@ for (int i = 1; i <= n; i++) {
相当于只需要把达到叶子节点的结果收集起来,就可以求得 n个数中k个数的组合集合。
-在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中我们提到了回溯法三部曲,那么我们按照回溯法三部曲开始正式讲解代码了。
+在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中我们提到了回溯法三部曲,那么我们按照回溯法三部曲开始正式讲解代码了。
## 回溯法三部曲
@@ -214,7 +214,7 @@ public:
};
```
-还记得我们在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中给出的回溯法模板么?
+还记得我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中给出的回溯法模板么?
如下:
```
diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md
index d545543d..171023dd 100644
--- a/problems/0077.组合优化.md
+++ b/problems/0077.组合优化.md
@@ -10,7 +10,7 @@
-在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。
+在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。
> 可以直接看我的B栈视频讲解:[带你学透回溯算法-组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er)
@@ -18,7 +18,7 @@
链接:https://leetcode-cn.com/problems/combinations/
-**看本篇之前,需要先看[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)**。
+**看本篇之前,需要先看[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)**。
大家先回忆一下[77. 组合]给出的回溯法的代码:
diff --git a/problems/0078.子集.md b/problems/0078.子集.md
index ca49f97b..583fe664 100644
--- a/problems/0078.子集.md
+++ b/problems/0078.子集.md
@@ -9,7 +9,7 @@
## 第78题. 子集
-题目地址:https://leetcode-cn.com/problems/subsets/
+[力扣题目链接](https://leetcode-cn.com/problems/subsets/)
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
@@ -31,7 +31,7 @@
## 思路
-求子集问题和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:分割问题!](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)又不一样了。
+求子集问题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:分割问题!](https://programmercarl.com/0131.分割回文串.html)又不一样了。
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,**那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!**
@@ -101,7 +101,7 @@ for (int i = startIndex; i < nums.size(); i++) {
## C++代码
-根据[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)给出的回溯算法模板:
+根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板:
```
void backtracking(参数) {
@@ -157,15 +157,15 @@ public:
相信大家经过了
* 组合问题:
- * [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)
- * [回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)
- * [回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)
- * [回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A)
- * [回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)
- * [回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)
+ * [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)
+ * [回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)
+ * [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)
+ * [回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
+ * [回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)
+ * [回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)
* 分割问题:
- * [回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)
- * [回溯算法:复原IP地址](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA)
+ * [回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)
+ * [回溯算法:复原IP地址](https://programmercarl.com/0093.复原IP地址.html)
洗礼之后,发现子集问题还真的有点简单了,其实这就是一道标准的模板题。
diff --git a/problems/0084.柱状图中最大的矩形.md b/problems/0084.柱状图中最大的矩形.md
index bec3bc99..a0f06e8f 100644
--- a/problems/0084.柱状图中最大的矩形.md
+++ b/problems/0084.柱状图中最大的矩形.md
@@ -2,7 +2,7 @@
# 84.柱状图中最大的矩形
-链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
+[力扣题目链接](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
@@ -15,9 +15,9 @@
# 思路
-本题和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
+本题和[42. 接雨水](https://programmercarl.com/0042.接雨水.html),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
-其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)
+其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://programmercarl.com/0042.接雨水.html)
我们先来看一下双指针的解法:
@@ -50,11 +50,11 @@ public:
## 动态规划
-本题动态规划的写法整体思路和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是一致的,但要比[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)难一些。
+本题动态规划的写法整体思路和[42. 接雨水](https://programmercarl.com/0042.接雨水.html)是一致的,但要比[42. 接雨水](https://programmercarl.com/0042.接雨水.html)难一些。
难就难在本题要记录记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。
-所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中已经介绍了。
+所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://programmercarl.com/0042.接雨水.html)中已经介绍了。
```CPP
class Solution {
@@ -95,11 +95,11 @@ public:
本地单调栈的解法和接雨水的题目是遥相呼应的。
-为什么这么说呢,[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
+为什么这么说呢,[42. 接雨水](https://programmercarl.com/0042.接雨水.html)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
**这里就涉及到了单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小**。
-在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
+在题解[42. 接雨水](https://programmercarl.com/0042.接雨水.html)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!
@@ -115,7 +115,7 @@ public:
理解这一点,对单调栈就掌握的比较到位了。
-除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
+除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[42. 接雨水](https://programmercarl.com/0042.接雨水.html)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
剩下就是分析清楚如下三种情况:
@@ -202,7 +202,6 @@ class Solution {
int length = heights.length;
int[] minLeftIndex = new int [length];
int[] maxRigthIndex = new int [length];
-
// 记录左边第一个小于该柱子的下标
minLeftIndex[0] = -1 ;
for (int i = 1; i < length; i++) {
diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md
index 5c19adc0..6dc631de 100644
--- a/problems/0090.子集II.md
+++ b/problems/0090.子集II.md
@@ -9,7 +9,7 @@
## 第90题.子集II
-题目链接:https://leetcode-cn.com/problems/subsets-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/subsets-ii/)
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
@@ -30,11 +30,11 @@
## 思路
-做本题之前一定要先做[78.子集](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)。
+做本题之前一定要先做[78.子集](https://programmercarl.com/0078.子集.html)。
-这道题目和[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)区别就是集合里有重复元素了,而且求取的子集要去重。
+这道题目和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
-那么关于回溯算法中的去重问题,**在[40.组合总和II](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)中已经详细讲解过了,和本题是一个套路**。
+那么关于回溯算法中的去重问题,**在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html)中已经详细讲解过了,和本题是一个套路**。
**剧透一下,后期要讲解的排列问题里去重也是这个套路,所以理解“树层去重”和“树枝去重”非常重要**。
@@ -44,11 +44,11 @@
从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!
-本题就是其实就是[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)也讲过了,所以我就直接给出代码了:
+本题就是其实就是[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)也讲过了,所以我就直接给出代码了:
## C++代码
-```
+```c++
class Solution {
private:
vector> result;
@@ -80,11 +80,10 @@ public:
return result;
}
};
-
```
使用set去重的版本。
-```
+```c++
class Solution {
private:
vector> result;
@@ -113,7 +112,6 @@ public:
return result;
}
};
-
```
## 补充
@@ -151,7 +149,6 @@ public:
return result;
}
};
-
```
## 总结
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md
index 74c6df77..9f2ea6e7 100644
--- a/problems/0093.复原IP地址.md
+++ b/problems/0093.复原IP地址.md
@@ -10,7 +10,7 @@
## 93.复原IP地址
-题目地址:https://leetcode-cn.com/problems/restore-ip-addresses/
+[力扣题目链接](https://leetcode-cn.com/problems/restore-ip-addresses/)
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
@@ -45,11 +45,11 @@ s 仅由数字组成
## 思路
-做这道题目之前,最好先把[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)这个做了。
+做这道题目之前,最好先把[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
这道题目相信大家刚看的时候,应该会一脸茫然。
-其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)就十分类似了。
+其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
切割问题可以抽象为树型结构,如图:
@@ -60,7 +60,7 @@ s 仅由数字组成
* 递归参数
-在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我们就提到切割问题类似组合问题。
+在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
@@ -76,7 +76,7 @@ startIndex一定是需要的,因为不能重复分割,记录下一层递归
* 递归终止条件
-终止条件和[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
+终止条件和[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
@@ -96,7 +96,7 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
* 单层搜索的逻辑
-在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中已经讲过在循环遍历中如何截取子串。
+在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
@@ -164,7 +164,7 @@ bool isValid(const string& s, int start, int end) {
## C++代码
-根据[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)给出的回溯算法模板:
+根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板:
```
void backtracking(参数) {
@@ -239,11 +239,11 @@ public:
## 总结
-在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我列举的分割字符串的难点,本题都覆盖了。
+在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
-可以说是[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)的加强版。
+可以说是[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md
index 7cbe4fec..68ab11c8 100644
--- a/problems/0096.不同的二叉搜索树.md
+++ b/problems/0096.不同的二叉搜索树.md
@@ -8,7 +8,7 @@
## 96.不同的二叉搜索树
-题目链接:https://leetcode-cn.com/problems/unique-binary-search-trees/
+[力扣题目链接](https://leetcode-cn.com/problems/unique-binary-search-trees/)
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
@@ -20,7 +20,7 @@
这道题目描述很简短,但估计大部分同学看完都是懵懵的状态,这得怎么统计呢?
-关于什么是二叉搜索树,我们之前在讲解二叉树专题的时候已经详细讲解过了,也可以看看这篇[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)在回顾一波。
+关于什么是二叉搜索树,我们之前在讲解二叉树专题的时候已经详细讲解过了,也可以看看这篇[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)在回顾一波。
了解了二叉搜索树之后,我们应该先举几个例子,画画图,看看有没有什么规律,如图:
diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md
index 6f7e5c14..6d054634 100644
--- a/problems/0098.验证二叉搜索树.md
+++ b/problems/0098.验证二叉搜索树.md
@@ -7,9 +7,9 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 98.验证二叉搜索树
+# 98.验证二叉搜索树
-题目地址:https://leetcode-cn.com/problems/validate-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/validate-binary-search-tree/)
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
@@ -22,7 +22,7 @@

-## 思路
+# 思路
要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
@@ -121,7 +121,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
要定义一个longlong的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。
-注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
+注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
其实本题是同样的道理,我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回。
@@ -210,7 +210,7 @@ public:
## 迭代法
-可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg),[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
+可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html),[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)
迭代法中序遍历稍加改动就可以了,代码如下:
@@ -240,9 +240,9 @@ public:
};
```
-在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
+在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
-## 总结
+# 总结
这道题目是一个简单题,但对于没接触过的同学还是有难度的。
@@ -251,10 +251,10 @@ public:
只要把基本类型的题目都做过,总结过之后,思路自然就开阔了。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -336,16 +336,10 @@ class Solution {
}
```
-Python:
+## Python
**递归** - 利用BST中序遍历特性,把树"压缩"成数组
```python
-# Definition for a binary tree node.
-# class TreeNode:
-# def __init__(self, val=0, left=None, right=None):
-# self.val = val
-# self.left = left
-# self.right = right
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
# 思路: 利用BST中序遍历的特性.
@@ -395,8 +389,9 @@ class Solution:
return is_left_valid and is_right_valid
return __isValidBST(root)
```
-```
-# 迭代-中序遍历
+
+```python
+迭代-中序遍历
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
stack = []
@@ -415,7 +410,8 @@ class Solution:
return True
```
-Go:
+## Go
+
```Go
import "math"
@@ -458,9 +454,9 @@ func isValidBST(root *TreeNode) bool {
}
```
-JavaScript版本
+## JavaScript
-> 辅助数组解决
+辅助数组解决
```javascript
/**
@@ -493,7 +489,7 @@ var isValidBST = function (root) {
};
```
-> 递归中解决
+递归中解决
```javascript
/**
diff --git a/problems/0100.相同的树.md b/problems/0100.相同的树.md
index df0a5dd1..6ffaf3cb 100644
--- a/problems/0100.相同的树.md
+++ b/problems/0100.相同的树.md
@@ -10,7 +10,7 @@
# 100. 相同的树
-题目地址:https://leetcode-cn.com/problems/same-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/same-tree/)
给定两个二叉树,编写一个函数来检验它们是否相同。
@@ -23,11 +23,11 @@
# 思路
-在[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中,我们讲到对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了**其实我们要比较的是两个树(这两个树是根节点的左右子树)**,所以在递归遍历的过程中,也是要同时遍历两棵树。
+在[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)中,我们讲到对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了**其实我们要比较的是两个树(这两个树是根节点的左右子树)**,所以在递归遍历的过程中,也是要同时遍历两棵树。
理解这一本质之后,就会发现,求二叉树是否对称,和求二叉树是否相同几乎是同一道题目。
-**如果没有读过[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)这一篇,请认真读完再做这道题,就会有感觉了。**
+**如果没有读过[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)这一篇,请认真读完再做这道题,就会有感觉了。**
递归三部曲中:
@@ -42,7 +42,7 @@
bool compare(TreeNode* tree1, TreeNode* tree2)
```
-分析过程同[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)。
+分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)。
2. 确定终止条件
@@ -68,7 +68,7 @@ else if (tree1 == NULL && tree2 == NULL) return true;
else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
```
-分析过程同[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)
+分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)
3. 确定单层递归的逻辑
diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md
index e091844b..03d3acaa 100644
--- a/problems/0101.对称二叉树.md
+++ b/problems/0101.对称二叉树.md
@@ -9,7 +9,7 @@
# 101. 对称二叉树
-题目地址:https://leetcode-cn.com/problems/symmetric-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/symmetric-tree/)
给定一个二叉树,检查它是否是镜像对称的。
diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md
index 45f7ee69..e62a3e66 100644
--- a/problems/0102.二叉树的层序遍历.md
+++ b/problems/0102.二叉树的层序遍历.md
@@ -20,7 +20,7 @@
* 104.二叉树的最大深度
* 111.二叉树的最小深度
-在之前写过这篇文章 [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog),可惜当时只打了5个,还不够,再给我一次机会,我打十个!
+在之前写过这篇文章 [二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),可惜当时只打了5个,还不够,再给我一次机会,我打十个!

@@ -28,7 +28,7 @@
# 102.二叉树的层序遍历
-题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/)
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
@@ -38,9 +38,9 @@
我们之前讲过了三篇关于二叉树的深度优先遍历的文章:
-* [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)
-* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)
-* [二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)
+* [二叉树:前中后序递归法](https://programmercarl.com/二叉树的递归遍历.html)
+* [二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)
+* [二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)
接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。
@@ -233,7 +233,7 @@ var levelOrder = function(root) {
# 107.二叉树的层次遍历 II
-题目链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/)
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
@@ -410,7 +410,7 @@ var levelOrderBottom = function(root) {
# 199.二叉树的右视图
-题目链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-right-side-view/)
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
@@ -587,7 +587,7 @@ var rightSideView = function(root) {
# 637.二叉树的层平均值
-题目链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/)
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
@@ -771,7 +771,7 @@ var averageOfLevels = function(root) {
# 429.N叉树的层序遍历
-题目链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
+[力扣题目链接](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/)
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
@@ -991,7 +991,7 @@ var levelOrder = function(root) {
# 515.在每个树行中找最大值
-题目链接:https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
+[力扣题目链接](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
您需要在二叉树的每一行中找到最大的值。
@@ -1072,32 +1072,6 @@ class Solution {
}
```
-```java
-//方法二:用一个max变量来保存最大值
-class Solution {
- public List largestValues(TreeNode root) {
- Queue queue = new LinkedList();
- List result = new ArrayList<>();
- if (root != null) queue.add(root);
-
- while(!queue.isEmpty()){
- int size = queue.size();
- int max = Integer.MIN_VALUE; // 初始化为最小值
- for(int i = 0; i < size; i++){
- TreeNode node = queue.poll();
- max = Math.max(node.val, max);
- if(node.left != null)
- queue.add(node.left);
- if(node.right != null)
- queue.add(node.right);
- }
- result.add(max); // 取最大值放进数组
- }
- return result;
- }
-}
-```
-
go:
```GO
@@ -1172,7 +1146,7 @@ var largestValues = function(root) {
# 116.填充每个节点的下一个右侧节点指针
-题目链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
+[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
@@ -1340,8 +1314,7 @@ func connect(root *Node) *Node {
# 117.填充每个节点的下一个右侧节点指针II
-
-题目地址:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
思路:
@@ -1503,7 +1476,7 @@ func connect(root *Node) *Node {
```
# 104.二叉树的最大深度
-题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
给定一个二叉树,找出其最大深度。
@@ -1588,7 +1561,7 @@ JavaScript:
# 111.二叉树的最小深度
-题目地址:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
相对于 104.二叉树的最大深度 ,本题还也可以使用层序遍历的方式来解决,思路是一样的。
@@ -1625,43 +1598,34 @@ public:
Java:
```java
class Solution {
-
public int minDepth(TreeNode root){
if (root == null) {
return 0;
}
-
Queue queue = new LinkedList<>();
queue.offer(root);
int depth = 0;
-
while (!queue.isEmpty()){
-
int size = queue.size();
depth++;
-
TreeNode cur = null;
for (int i = 0; i < size; i++) {
cur = queue.poll();
-
//如果当前节点的左右孩子都为空,直接返回最小深度
if (cur.left == null && cur.right == null){
return depth;
}
-
if (cur.left != null) queue.offer(cur.left);
if (cur.right != null) queue.offer(cur.right);
}
-
-
}
-
return depth;
}
}
```
+
Python 3:
```python 3
diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md
index f09361e1..d086686d 100644
--- a/problems/0104.二叉树的最大深度.md
+++ b/problems/0104.二叉树的最大深度.md
@@ -14,7 +14,7 @@
# 104.二叉树的最大深度
-题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
给定一个二叉树,找出其最大深度。
@@ -127,7 +127,7 @@ public:
return result;
}
};
-```
+```
**可以看出使用了前序(中左右)的遍历顺序,这才是真正求深度的逻辑!**
@@ -167,7 +167,7 @@ public:
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
-如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
+如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
c++代码如下:
@@ -198,7 +198,7 @@ public:
# 559.n叉树的最大深度
-题目地址:https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/)
给定一个 n 叉树,找到其最大深度。
@@ -481,7 +481,7 @@ var maxdepth = function(root) {
if (!root) return root
return 1 + math.max(maxdepth(root.left), maxdepth(root.right))
};
-```
+```
二叉树最大深度递归遍历
```javascript
diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md
index 4cfe2858..39b55d8c 100644
--- a/problems/0106.从中序与后序遍历序列构造二叉树.md
+++ b/problems/0106.从中序与后序遍历序列构造二叉树.md
@@ -12,9 +12,9 @@
* 106.从中序与后序遍历序列构造二叉树
* 105.从前序与中序遍历序列构造二叉树
-## 106.从中序与后序遍历序列构造二叉树
+# 106.从中序与后序遍历序列构造二叉树
-题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
+[力扣题目链接](https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)
根据一棵树的中序遍历与后序遍历构造二叉树。
@@ -29,7 +29,7 @@

-### 思路
+## 思路
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
@@ -95,7 +95,7 @@ TreeNode* traversal (vector& inorder, vector& postorder) {
**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭又闭,必然乱套!**
-我在[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)和[数组:这个循环可以转懵很多人!](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
+我在[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0035.搜索插入位置.html)和[数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
首先要切割中序数组,为什么先切割中序数组呢?
@@ -105,7 +105,7 @@ TreeNode* traversal (vector& inorder, vector& postorder) {
中序数组相对比较好切,找到切割点(后序数组的最后一个元素)在中序数组的位置,然后切割,如下代码中我坚持左闭右开的原则:
-```
+```C++
// 找到中序遍历的切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
@@ -394,9 +394,9 @@ public:
};
```
-## 105.从前序与中序遍历序列构造二叉树
+# 105.从前序与中序遍历序列构造二叉树
-题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
+[力扣题目链接](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/)
根据一棵树的前序遍历与中序遍历构造二叉树。
@@ -411,7 +411,7 @@ public:

-### 思路
+## 思路
本题和106是一样的道理。
@@ -540,7 +540,7 @@ public:
};
```
-## 思考题
+# 思考题
前序和中序可以唯一确定一颗二叉树。
@@ -562,7 +562,7 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
所以前序和后序不能唯一确定一颗二叉树!
-## 总结
+# 总结
之前我们讲的二叉树题目都是各种遍历二叉树,这次开始构造二叉树了,思路其实比较简单,但是真正代码实现出来并不容易。
@@ -578,9 +578,9 @@ tree2 的前序遍历是[1 2 3], 后序遍历是[3 2 1]。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
106.从中序与后序遍历序列构造二叉树
@@ -653,7 +653,7 @@ class Solution {
}
```
-Python:
+## Python
105.从前序与中序遍历序列构造二叉树
@@ -685,7 +685,8 @@ class Solution:
root.right = self.buildTree(preorder_right, inorder_right)
return root
-```
+```
+
106.从中序与后序遍历序列构造二叉树
```python
@@ -716,9 +717,11 @@ class Solution:
root.right = self.buildTree(inorder_right, postorder_right)
return root
-```
-Go:
-> 106 从中序与后序遍历序列构造二叉树
+```
+
+## Go
+
+106 从中序与后序遍历序列构造二叉树
```go
/**
@@ -751,7 +754,7 @@ func findRootIndex(inorder []int,target int) (index int){
}
```
-> 105 从前序与中序遍历序列构造二叉树
+105 从前序与中序遍历序列构造二叉树
```go
/**
@@ -784,7 +787,8 @@ func findRootIndex(target int,inorder []int) int{
-JavaScript
+## JavaScript
+
```javascript
var buildTree = function(inorder, postorder) {
if (!postorder.length) return null
diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md
index 9e67a677..5f99f98a 100644
--- a/problems/0108.将有序数组转换为二叉搜索树.md
+++ b/problems/0108.将有序数组转换为二叉搜索树.md
@@ -11,7 +11,7 @@
## 108.将有序数组转换为二叉搜索树
-题目链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/)
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
@@ -25,10 +25,10 @@
做这道题目之前大家可以了解一下这几道:
-* [106.从中序与后序遍历序列构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)
-* [654.最大二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。
-* [701.二叉搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)
-* [450.删除二叉搜索树中的节点](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw)
+* [106.从中序与后序遍历序列构造二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)
+* [654.最大二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树。
+* [701.二叉搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)
+* [450.删除二叉搜索树中的节点](https://programmercarl.com/0450.删除二叉搜索树中的节点.html)
进入正题:
@@ -38,11 +38,11 @@
其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**。
-在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)和[二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。
+在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)和[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树。
**本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间**。
-本题其实要比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。
+本题其实要比[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。
分割点就是数组中间位置的节点。
@@ -68,11 +68,11 @@
删除二叉树节点,增加二叉树节点,都是用递归函数的返回值来完成,这样是比较方便的。
-相信大家如果仔细看了[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)和[二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw),一定会对递归函数返回值的作用深有感触。
+相信大家如果仔细看了[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)和[二叉树:搜索树中的删除操作](https://programmercarl.com/0450.删除二叉搜索树中的节点.html),一定会对递归函数返回值的作用深有感触。
那么本题要构造二叉树,依然用递归函数的返回值来构造中节点的左右孩子。
-再来看参数,首先是传入数组,然后就是左下表left和右下表right,我们在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下表来操作原数组。
+再来看参数,首先是传入数组,然后就是左下表left和右下表right,我们在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下表来操作原数组。
所以代码如下:
@@ -83,7 +83,7 @@ TreeNode* traversal(vector& nums, int left, int right)
这里注意,**我这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及到我们讲过的循环不变量**。
-在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg),[35.搜索插入位置](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q) 和[59.螺旋矩阵II](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)都详细讲过循环不变量。
+在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html),[35.搜索插入位置](https://programmercarl.com/0035.搜索插入位置.html) 和[59.螺旋矩阵II](https://programmercarl.com/0059.螺旋矩阵II.html)都详细讲过循环不变量。
* 确定递归终止条件
@@ -98,7 +98,7 @@ if (left > right) return nullptr;
* 确定单层递归的逻辑
-首先取数组中间元素的位置,不难写出`int mid = (left + right) / 2;`,**这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在[二分法](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)中尤其需要注意!**
+首先取数组中间元素的位置,不难写出`int mid = (left + right) / 2;`,**这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在[二分法](https://programmercarl.com/0035.搜索插入位置.html)中尤其需要注意!**
所以可以这么写:`int mid = left + ((right - left) / 2);`
@@ -194,7 +194,7 @@ public:
## 总结
-**在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
+**在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
其实思路也是一样的,不断中间分割,然后递归处理左区间,右区间,也可以说是分治。
diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md
index 55d3c2e7..43a49758 100644
--- a/problems/0110.平衡二叉树.md
+++ b/problems/0110.平衡二叉树.md
@@ -11,7 +11,7 @@
# 110.平衡二叉树
-题目地址:https://leetcode-cn.com/problems/balanced-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/balanced-binary-tree/)
给定一个二叉树,判断它是否是高度平衡的二叉树。
@@ -36,7 +36,7 @@
# 题外话
-咋眼一看这道题目和[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)很像,其实有很大区别。
+咋眼一看这道题目和[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)很像,其实有很大区别。
这里强调一波概念:
@@ -51,11 +51,11 @@
因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
-有的同学一定疑惑,为什么[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中求的是二叉树的最大深度,也用的是后序遍历。
+有的同学一定疑惑,为什么[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中求的是二叉树的最大深度,也用的是后序遍历。
**那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这颗树的最大深度,所以才可以使用后序遍历。**
-在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
+在[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
```CPP
class Solution {
@@ -228,7 +228,7 @@ public:
## 迭代
-在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
+在[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
本题的迭代方式可以先定义一个函数,专门用来求高度。
diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md
index b4d0e32b..12eadd60 100644
--- a/problems/0111.二叉树的最小深度.md
+++ b/problems/0111.二叉树的最小深度.md
@@ -11,7 +11,7 @@
# 111.二叉树的最小深度
-题目地址:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
给定一个二叉树,找出其最小深度。
@@ -29,7 +29,7 @@
# 思路
-看完了这篇[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),再来看看如何求最小深度。
+看完了这篇[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),再来看看如何求最小深度。
直觉上好像和求最大深度差不多,其实还是差不少的。
@@ -154,9 +154,9 @@ public:
## 迭代法
-相对于[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),本题还可以使用层序遍历的方式来解决,思路是一样的。
+相对于[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),本题还可以使用层序遍历的方式来解决,思路是一样的。
-如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
+如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
**需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点**
diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md
index 4a814ee1..283a9913 100644
--- a/problems/0112.路径总和.md
+++ b/problems/0112.路径总和.md
@@ -18,7 +18,7 @@
# 112. 路径总和
-题目地址:https://leetcode-cn.com/problems/path-sum/
+[力扣题目链接](https://leetcode-cn.com/problems/path-sum/)
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
@@ -46,7 +46,7 @@
再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
* 如果需要搜索整颗二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
-* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中介绍)
+* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中介绍)
* 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
而本题我们要找一条符合条件的路径,所以递归函数需要返回值,及时返回,那么返回类型是什么呢?
@@ -218,7 +218,7 @@ public:
# 113. 路径总和ii
-题目地址:https://leetcode-cn.com/problems/path-sum-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/path-sum-ii/)
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
diff --git a/problems/0115.不同的子序列.md b/problems/0115.不同的子序列.md
index e964e95d..a5162ae0 100644
--- a/problems/0115.不同的子序列.md
+++ b/problems/0115.不同的子序列.md
@@ -8,7 +8,7 @@
## 115.不同的子序列
-题目链接:https://leetcode-cn.com/problems/distinct-subsequences/
+[力扣题目链接](https://leetcode-cn.com/problems/distinct-subsequences/)
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
@@ -29,7 +29,7 @@ s 和 t 由英文字母组成
这道题目相对于72. 编辑距离,简单了不少,因为本题相当于只有删除操作,不用考虑替换增加之类的。
-但相对于刚讲过的[动态规划:392.判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng)就有难度了,这道题目双指针法可就做不了了,来看看动规五部曲分析如下:
+但相对于刚讲过的[动态规划:392.判断子序列](https://programmercarl.com/0392.判断子序列.html)就有难度了,这道题目双指针法可就做不了了,来看看动规五部曲分析如下:
1. 确定dp数组(dp table)以及下标的含义
diff --git a/problems/0116.填充每个节点的下一个右侧节点指针.md b/problems/0116.填充每个节点的下一个右侧节点指针.md
index 34c666f3..e43d79b0 100644
--- a/problems/0116.填充每个节点的下一个右侧节点指针.md
+++ b/problems/0116.填充每个节点的下一个右侧节点指针.md
@@ -9,7 +9,7 @@
# 116. 填充每个节点的下一个右侧节点指针
-链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
+[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
@@ -87,7 +87,7 @@ public:
## 迭代(层序遍历)
-本题使用层序遍历是最为直观的,如果对层序遍历不了解,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)。
+本题使用层序遍历是最为直观的,如果对层序遍历不了解,看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)。
层序遍历本来就是一层一层的去遍历,记录一层的头结点(nodePre),然后让nodePre指向当前遍历的节点就可以了。
diff --git a/problems/0121.买卖股票的最佳时机.md b/problems/0121.买卖股票的最佳时机.md
index 6d068c22..daeb05a9 100644
--- a/problems/0121.买卖股票的最佳时机.md
+++ b/problems/0121.买卖股票的最佳时机.md
@@ -8,7 +8,7 @@
## 121. 买卖股票的最佳时机
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md
index 53737532..ff1b6d4a 100644
--- a/problems/0122.买卖股票的最佳时机II.md
+++ b/problems/0122.买卖股票的最佳时机II.md
@@ -9,7 +9,7 @@
## 122.买卖股票的最佳时机II
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
diff --git a/problems/0122.买卖股票的最佳时机II(动态规划).md b/problems/0122.买卖股票的最佳时机II(动态规划).md
index 7492ee04..5dfe3f0e 100644
--- a/problems/0122.买卖股票的最佳时机II(动态规划).md
+++ b/problems/0122.买卖股票的最佳时机II(动态规划).md
@@ -8,7 +8,7 @@
## 122.买卖股票的最佳时机II
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
@@ -38,12 +38,12 @@
## 思路
-本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。
+本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。
-本题和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的唯一区别本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票)
+本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的唯一区别本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票)
-**在动规五部曲中,这个区别主要是体现在递推公式上,其他都和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)一样一样的**。
+**在动规五部曲中,这个区别主要是体现在递推公式上,其他都和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)一样一样的**。
所以我们重点讲一讲递推公式。
@@ -57,10 +57,9 @@
* 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
* 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]
+**注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。
-**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。
-
-在[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。
+在[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。
而本题,因为一只股票可以买卖多次,所以当第i天买入股票的时候,所持有的现金可能有之前买卖过的利润。
@@ -70,7 +69,7 @@
* 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
* 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0]
-**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)就是一样的逻辑,卖出股票收获利润(可能是负值)天经地义!**
+**注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)就是一样的逻辑,卖出股票收获利润(可能是负值)天经地义!**
代码如下:(注意代码中的注释,标记了和121.买卖股票的最佳时机唯一不同的地方)
@@ -94,7 +93,7 @@ public:
* 时间复杂度:O(n)
* 空间复杂度:O(n)
-大家可以本题和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的代码几乎一样,唯一的区别在:
+大家可以本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的代码几乎一样,唯一的区别在:
```
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
@@ -122,7 +121,7 @@ public:
return dp[(len - 1) % 2][1];
}
};
-```
+```
* 时间复杂度:O(n)
* 空间复杂度:O(1)
diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md
index 0c92a5a2..6a849c80 100644
--- a/problems/0123.买卖股票的最佳时机III.md
+++ b/problems/0123.买卖股票的最佳时机III.md
@@ -8,7 +8,7 @@
## 123.买卖股票的最佳时机III
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/)
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
@@ -44,7 +44,7 @@
## 思路
-这道题目相对 [121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) 和 [122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 难了不少。
+这道题目相对 [121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html) 和 [122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html) 难了不少。
关键在于至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。
diff --git a/problems/0129.求根到叶子节点数字之和.md b/problems/0129.求根到叶子节点数字之和.md
index 17642793..3439cd25 100644
--- a/problems/0129.求根到叶子节点数字之和.md
+++ b/problems/0129.求根到叶子节点数字之和.md
@@ -1,13 +1,13 @@
## 链接
-https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
+[力扣题目链接](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/)
## 思路
-本题和[113.路径总和II](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 和 [112.路径总和](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 做了。
+本题和[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii) 和 [112.路径总和](https://programmercarl.com/0112.路径总和.html#_112-路径总和) 做了。
-结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
+结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
-接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)中,我详细讲解了二叉树的递归中,如何使用了回溯。
+接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)中,我详细讲解了二叉树的递归中,如何使用了回溯。
接下来我们来看题:
@@ -17,11 +17,11 @@ https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
### 递归三部曲
-如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
+如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://programmercarl.com/二叉树的递归遍历.html)
* 确定递归函数返回值及其参数
-这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中,详细讲解了返回值问题。
+这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中,详细讲解了返回值问题。
参数只需要把根节点传入,此时还需要定义两个全局遍历,一个是result,记录最终结果,一个是vector path。
diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md
index afb8cbb7..f2e108e8 100644
--- a/problems/0131.分割回文串.md
+++ b/problems/0131.分割回文串.md
@@ -11,7 +11,7 @@
## 131.分割回文串
-题目链接:https://leetcode-cn.com/problems/palindrome-partitioning/
+[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning/)
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
@@ -66,7 +66,7 @@
本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致的。
-在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)中我们深入探讨了组合问题什么时候需要startIndex,什么时候不需要startIndex。
+在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)中我们深入探讨了组合问题什么时候需要startIndex,什么时候不需要startIndex。
代码如下:
@@ -143,7 +143,7 @@ for (int i = startIndex; i < s.size(); i++) {
}
```
-如果大家对双指针法有生疏了,传送门:[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA)
+如果大家对双指针法有生疏了,传送门:[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)
此时关键代码已经讲解完毕,整体代码如下(详细注释了)
diff --git a/problems/0132.分割回文串II.md b/problems/0132.分割回文串II.md
index 80784301..dbd830d0 100644
--- a/problems/0132.分割回文串II.md
+++ b/problems/0132.分割回文串II.md
@@ -10,7 +10,7 @@
# 132. 分割回文串 II
-链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
@@ -29,7 +29,7 @@
示例 3:
输入:s = "ab"
输出:1
-
+
提示:
@@ -38,7 +38,7 @@
# 思路
-我们在讲解回溯法系列的时候,讲过了这道题目[回溯算法:131.分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)。
+我们在讲解回溯法系列的时候,讲过了这道题目[回溯算法:131.分割回文串](https://programmercarl.com/0131.分割回文串.html)。
本题呢其实也可以使用回溯法,只不过会超时!(通过记忆化回溯,也可以过,感兴趣的同学可以自行研究一下)
@@ -46,7 +46,7 @@
关于回文子串,两道题目题目大家是一定要掌握的。
-* [动态规划:647. 回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw)
+* [动态规划:647. 回文子串](https://programmercarl.com/0647.回文子串.html)
* 5.最长回文子串 和 647.回文子串基本一样的
这两道题目是回文子串的基础题目,本题也要用到相关的知识点。
diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md
index e270c059..0befd085 100644
--- a/problems/0134.加油站.md
+++ b/problems/0134.加油站.md
@@ -9,7 +9,7 @@
## 134. 加油站
-题目链接:https://leetcode-cn.com/problems/gas-station/
+[力扣题目链接](https://leetcode-cn.com/problems/gas-station/)
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
diff --git a/problems/0135.分发糖果.md b/problems/0135.分发糖果.md
index 3865e14b..526b5870 100644
--- a/problems/0135.分发糖果.md
+++ b/problems/0135.分发糖果.md
@@ -9,7 +9,7 @@
## 135. 分发糖果
-链接:https://leetcode-cn.com/problems/candy/
+[力扣题目链接](https://leetcode-cn.com/problems/candy/)
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md
index 0c19a614..969d2ce7 100644
--- a/problems/0139.单词拆分.md
+++ b/problems/0139.单词拆分.md
@@ -10,7 +10,7 @@
## 139.单词拆分
-题目链接:https://leetcode-cn.com/problems/word-break/
+[力扣题目链接](https://leetcode-cn.com/problems/word-break/)
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
@@ -37,9 +37,9 @@
## 思路
-看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q),就是枚举字符串的所有分割情况。
+看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html),就是枚举字符串的所有分割情况。
-[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q):是枚举分割后的所有子串,判断是否回文。
+[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html):是枚举分割后的所有子串,判断是否回文。
本道是枚举分割所有字符串,判断是否在字典里出现过。
@@ -161,11 +161,11 @@ dp[0]表示如果字符串为空的话,说明出现在字典里。
**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
-对这个结论还有疑问的同学可以看这篇[本周小结!(动态规划系列五)](https://mp.weixin.qq.com/s/znj-9j8mWymRFaPjJN2Qnw),这篇本周小节中,我做了如下总结:
+对这个结论还有疑问的同学可以看这篇[本周小结!(动态规划系列五)](https://programmercarl.com/%E5%91%A8%E6%80%BB%E7%BB%93/20210204动规周末总结.html),这篇本周小节中,我做了如下总结:
-求组合数:[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)
-求排列数:[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA)
-求最小数:[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)、[动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ)
+求组合数:[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)
+求排列数:[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和.html)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
+求最小数:[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
本题最终要求的是是否都出现过,所以对出现单词集合里的元素是组合还是排列,并不在意!
@@ -215,7 +215,7 @@ public:
## 总结
-本题和我们之前讲解回溯专题的[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)非常像,所以我也给出了对应的回溯解法。
+本题和我们之前讲解回溯专题的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)非常像,所以我也给出了对应的回溯解法。
稍加分析,便可知道本题是完全背包,而且是求能否组成背包,所以遍历顺序理论上来讲 两层for循环谁先谁后都可以!
diff --git a/problems/0141.环形链表.md b/problems/0141.环形链表.md
index 78bcfd43..34b8d25f 100644
--- a/problems/0141.环形链表.md
+++ b/problems/0141.环形链表.md
@@ -66,7 +66,7 @@ public:
做完这道题目,可以在做做142.环形链表II,不仅仅要找环,还要找环的入口。
-142.环形链表II题解:[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
+142.环形链表II题解:[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)
# 其他语言版本
diff --git a/problems/0142.环形链表II.md b/problems/0142.环形链表II.md
index 91e14e27..bfa779a2 100644
--- a/problems/0142.环形链表II.md
+++ b/problems/0142.环形链表II.md
@@ -13,7 +13,7 @@
## 142.环形链表II
-https://leetcode-cn.com/problems/linked-list-cycle-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/linked-list-cycle-ii/)
题意:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
@@ -146,7 +146,7 @@ public:
在推理过程中,大家可能有一个疑问就是:**为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢?**
-即文章[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)中如下的地方:
+即文章[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中如下的地方:

@@ -175,7 +175,7 @@ public:
那有同学又说了,为什么fast不能跳过去呢? 在刚刚已经说过一次了,**fast相对于slow是一次移动一个节点,所以不可能跳过去**。
-好了,这次把为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y ,用数学推理了一下,算是对[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)的补充。
+好了,这次把为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y ,用数学推理了一下,算是对[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)的补充。
## 总结
@@ -296,6 +296,39 @@ var detectCycle = function(head) {
};
```
+Swift:
+```swift
+class Solution {
+ func detectCycle(_ head: ListNode?) -> ListNode? {
+ var slow: ListNode? = head
+ var fast: ListNode? = head
+ while fast != nil && fast?.next != nil {
+ slow = slow?.next
+ fast = fast?.next?.next
+ if slow == fast {
+ // 环内相遇
+ var list1: ListNode? = slow
+ var list2: ListNode? = head
+ while list1 != list2 {
+ list1 = list1?.next
+ list2 = list2?.next
+ }
+ return list2
+ }
+ }
+ return nil
+ }
+}
+extension ListNode: Equatable {
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(val)
+ hasher.combine(ObjectIdentifier(self))
+ }
+ public static func == (lhs: ListNode, rhs: ListNode) -> Bool {
+ return lhs === rhs
+ }
+}
+```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md
index bcde7d5b..7eb5bc00 100644
--- a/problems/0150.逆波兰表达式求值.md
+++ b/problems/0150.逆波兰表达式求值.md
@@ -13,7 +13,7 @@
# 150. 逆波兰表达式求值
-https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
+[力扣题目链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/)
根据 逆波兰表示法,求表达式的值。
@@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
-
+
示例 1:
* 输入: ["2", "1", "+", "3", " * "]
@@ -40,13 +40,13 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
* 输出: 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
-
+ = ((10 * (6 / (12 * -11))) + 17) + 5
+ = ((10 * (6 / -132)) + 17) + 5
+ = ((10 * 0) + 17) + 5
+ = (0 + 17) + 5
+ = 17 + 5
+ = 22
+
逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。
@@ -62,7 +62,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
# 思路
-在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)提到了 递归就是用栈来实现的。
+在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。
所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。
@@ -70,12 +70,12 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。
-在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中的对对碰游戏是不是就非常像了。**
+在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。**
如动画所示:

-相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
+相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
C++代码如下:
@@ -223,19 +223,17 @@ var evalRPN = function(tokens) {
python3
```python
-class Solution:
- def evalRPN(self, tokens: List[str]) -> int:
- stack = []
- for item in tokens:
- if item not in {"+", "-", "*", "/"}:
- stack.append(item)
- else:
- first_num, second_num = stack.pop(), stack.pop()
- stack.append(
- int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面
- )
- return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的
-
+def evalRPN(tokens) -> int:
+ stack = list()
+ for i in range(len(tokens)):
+ if tokens[i] not in ["+", "-", "*", "/"]:
+ stack.append(tokens[i])
+ else:
+ tmp1 = stack.pop()
+ tmp2 = stack.pop()
+ res = eval(tmp2+tokens[i]+tmp1)
+ stack.append(str(int(res)))
+ return stack[-1]
```
diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md
index 3f4d00b2..84e348a9 100644
--- a/problems/0151.翻转字符串里的单词.md
+++ b/problems/0151.翻转字符串里的单词.md
@@ -12,7 +12,7 @@
# 151.翻转字符串里的单词
-https://leetcode-cn.com/problems/reverse-words-in-a-string/
+[力扣题目链接](https://leetcode-cn.com/problems/reverse-words-in-a-string/)
给定一个字符串,逐个翻转字符串中的每个单词。
@@ -83,13 +83,13 @@ void removeExtraSpaces(string& s) {
如果不仔细琢磨一下erase的时间复杂读,还以为以上的代码是O(n)的时间复杂度呢。
-想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww),最优的算法来移除元素也要O(n)。
+想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html),最优的算法来移除元素也要O(n)。
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
-如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)是如何移除元素的。
+如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)是如何移除元素的。
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
@@ -125,7 +125,7 @@ void removeExtraSpaces(string& s) {
此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
-还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)和[541.反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)里已经讲过了。
+还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)和[541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)里已经讲过了。
代码如下:
diff --git a/problems/0160.相交链表.md b/problems/0160.相交链表.md
index 7ac1848b..42b2ee56 100644
--- a/problems/0160.相交链表.md
+++ b/problems/0160.相交链表.md
@@ -1,3 +1,3 @@
-同:[链表:链表相交](./面试题02.07.链表相交.md)
+同:[链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)
diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md
index 66676a7a..bcb8a1ab 100644
--- a/problems/0188.买卖股票的最佳时机IV.md
+++ b/problems/0188.买卖股票的最佳时机IV.md
@@ -8,7 +8,7 @@
## 188.买卖股票的最佳时机IV
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/)
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
@@ -35,13 +35,13 @@
## 思路
-这道题目可以说是[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)的进阶版,这里要求至多有k次交易。
+这道题目可以说是[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)的进阶版,这里要求至多有k次交易。
动规五部曲,分析如下:
1. 确定dp数组以及下标的含义
-在[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)中,我是定义了一个二维dp数组,本题其实依然可以用一个二维dp数组。
+在[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)中,我是定义了一个二维dp数组,本题其实依然可以用一个二维dp数组。
使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
@@ -91,7 +91,7 @@ for (int j = 0; j < 2 * k - 1; j += 2) {
}
```
-**本题和[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。
+**本题和[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。
3. dp数组如何初始化
diff --git a/problems/0189.旋转数组.md b/problems/0189.旋转数组.md
index be46bf4c..ba6edd1f 100644
--- a/problems/0189.旋转数组.md
+++ b/problems/0189.旋转数组.md
@@ -37,17 +37,17 @@
这道题目在字符串里其实很常见,我把字符串反转相关的题目列一下:
-* [字符串:力扣541.反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)
-* [字符串:力扣151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)
-* [字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)
+* [字符串:力扣541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)
+* [字符串:力扣151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)
+* [字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)
-本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)就非常像了,剑指offer上左旋转,本题是右旋转。
+本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)就非常像了,剑指offer上左旋转,本题是右旋转。
注意题目要求是**要求使用空间复杂度为 O(1) 的 原地 算法**
那么我来提供一种旋转的方式哈。
-在[字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)中,我们提到,如下步骤就可以坐旋转字符串:
+在[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)中,我们提到,如下步骤就可以坐旋转字符串:
1. 反转区间为前n的子串
2. 反转区间为n到末尾的子串
diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md
index 93b56dae..c8645c48 100644
--- a/problems/0198.打家劫舍.md
+++ b/problems/0198.打家劫舍.md
@@ -8,7 +8,7 @@
## 198.打家劫舍
-题目链接:https://leetcode-cn.com/problems/house-robber/
+[力扣题目链接](https://leetcode-cn.com/problems/house-robber/)
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md
index 2e784e6a..b9386a68 100644
--- a/problems/0202.快乐数.md
+++ b/problems/0202.快乐数.md
@@ -12,7 +12,7 @@
# 第202题. 快乐数
-https://leetcode-cn.com/problems/happy-number/
+[力扣题目链接](https://leetcode-cn.com/problems/happy-number/)
编写一个算法来判断一个数 n 是不是快乐数。
@@ -36,7 +36,7 @@ https://leetcode-cn.com/problems/happy-number/
题目中说了会 **无限循环**,那么也就是说**求和的过程中,sum会重复出现,这对解题很重要!**
-正如:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中所说,**当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。**
+正如:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中所说,**当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。**
所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md
index d67a7d2a..555dad03 100644
--- a/problems/0203.移除链表元素.md
+++ b/problems/0203.移除链表元素.md
@@ -11,7 +11,7 @@
# 203.移除链表元素
-https://leetcode-cn.com/problems/remove-linked-list-elements/
+[力扣题目链接](https://leetcode-cn.com/problems/remove-linked-list-elements/)
题意:删除链表中等于给定值 val 的所有节点。
@@ -245,15 +245,13 @@ Python:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
-
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
- dummy_head = ListNode(next=head)
+ dummy_head = ListNode(next=head) #添加一个虚拟节点
cur = dummy_head
-
- while cur.next:
- if cur.next.val == val:
- cur.next = cur.next.next # 删除下一个节点
+ while(cur.next!=None):
+ if(cur.next.val == val):
+ cur.next = cur.next.next #删除cur.next节点
else:
cur = cur.next
return dummy_head.next
diff --git a/problems/0205.同构字符串.md b/problems/0205.同构字符串.md
index d5077e03..5b0dd82b 100644
--- a/problems/0205.同构字符串.md
+++ b/problems/0205.同构字符串.md
@@ -9,7 +9,7 @@
# 205. 同构字符串
-题目地址:https://leetcode-cn.com/problems/isomorphic-strings/
+[力扣题目链接](https://leetcode-cn.com/problems/isomorphic-strings/)
给定两个字符串 s 和 t,判断它们是否是同构的。
diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md
index 0c850d52..45196386 100644
--- a/problems/0206.翻转链表.md
+++ b/problems/0206.翻转链表.md
@@ -11,7 +11,7 @@
# 206.反转链表
-https://leetcode-cn.com/problems/reverse-linked-list/
+[力扣题目链接](https://leetcode-cn.com/problems/reverse-linked-list/)
题意:反转一个单链表。
diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md
index 3219d16f..45d2a229 100644
--- a/problems/0209.长度最小的子数组.md
+++ b/problems/0209.长度最小的子数组.md
@@ -9,7 +9,7 @@
## 209.长度最小的子数组
-题目链接: https://leetcode-cn.com/problems/minimum-size-subarray-sum/
+[力扣题目链接](https://leetcode-cn.com/problems/minimum-size-subarray-sum/)
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md
index e828d17a..332d3218 100644
--- a/problems/0213.打家劫舍II.md
+++ b/problems/0213.打家劫舍II.md
@@ -8,7 +8,7 @@
## 213.打家劫舍II
-题目链接:https://leetcode-cn.com/problems/house-robber-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/house-robber-ii/)
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
@@ -28,14 +28,14 @@
示例 3:
输入:nums = [0]
输出:0
-
+
提示:
* 1 <= nums.length <= 100
* 0 <= nums[i] <= 1000
## 思路
-这道题目和[198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)是差不多的,唯一区别就是成环了。
+这道题目和[198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)是差不多的,唯一区别就是成环了。
对于一个数组,成环的话主要有如下三种情况:
@@ -55,7 +55,7 @@
**而情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了**。
-分析到这里,本题其实比较简单了。 剩下的和[198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)就是一样的了。
+分析到这里,本题其实比较简单了。 剩下的和[198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)就是一样的了。
代码如下:
diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md
index c9cfa973..177c6b03 100644
--- a/problems/0216.组合总和III.md
+++ b/problems/0216.组合总和III.md
@@ -13,7 +13,7 @@
# 216.组合总和III
-链接:https://leetcode-cn.com/problems/combination-sum-iii/
+[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-iii/)
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
@@ -34,9 +34,9 @@
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。
-相对于[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。
+相对于[77. 组合](https://programmercarl.com/0077.组合.html),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。
-想到这一点了,做过[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)之后,本题是简单一些了。
+想到这一点了,做过[77. 组合](https://programmercarl.com/0077.组合.html)之后,本题是简单一些了。
本题k相当于了树的深度,9(因为整个集合就是9个数)就是树的宽度。
@@ -53,7 +53,7 @@
* **确定递归函数参数**
-和[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。
+和[77. 组合](https://programmercarl.com/0077.组合.html)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。
这里我依然定义path 和 result为全局变量。
@@ -103,7 +103,7 @@ if (path.size() == k) {
* **单层搜索过程**
-本题和[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)区别之一就是集合固定的就是9个数[1,...,9],所以for循环固定i<=9
+本题和[77. 组合](https://programmercarl.com/0077.组合.html)区别之一就是集合固定的就是9个数[1,...,9],所以for循环固定i<=9
如图:

@@ -124,7 +124,7 @@ for (int i = startIndex; i <= 9; i++) {
**别忘了处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减!**
-参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
+参照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的模板,不难写出如下C++代码:
```CPP
class Solution {
@@ -176,7 +176,7 @@ if (sum > targetSum) { // 剪枝操作
}
```
-和[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA) 一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
+和[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html) 一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
最后C++代码如下:
@@ -214,7 +214,7 @@ public:
# 总结
-开篇就介绍了本题与[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)的区别,相对来说加了元素总和的限制,如果做完[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)再做本题在合适不过。
+开篇就介绍了本题与[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)的区别,相对来说加了元素总和的限制,如果做完[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)再做本题在合适不过。
分析完区别,依然把问题抽象为树形结构,按照回溯三部曲进行讲解,最后给出剪枝的优化。
diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md
index 0d3a818e..6268c447 100644
--- a/problems/0222.完全二叉树的节点个数.md
+++ b/problems/0222.完全二叉树的节点个数.md
@@ -9,7 +9,7 @@
# 222.完全二叉树的节点个数
-题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/
+[力扣题目链接](https://leetcode-cn.com/problems/count-complete-tree-nodes/)
给出一个完全二叉树,求出该树的节点个数。
@@ -41,13 +41,13 @@
首先按照普通二叉树的逻辑来求。
-这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
+这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
递归遍历的顺序依然是后序(左右中)。
### 递归
-如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)。
+如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)。
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
@@ -115,7 +115,7 @@ public:
### 迭代法
-如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)。
+如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)。
那么只要模板少做改动,加一个变量result,统计节点数量就可以了
@@ -145,7 +145,7 @@ public:
## 完全二叉树
-以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA),这篇详细介绍了各种二叉树的特性。
+以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html),这篇详细介绍了各种二叉树的特性。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md
index ccf93f1f..d6386cee 100644
--- a/problems/0225.用队列实现栈.md
+++ b/problems/0225.用队列实现栈.md
@@ -12,7 +12,7 @@
# 225. 用队列实现栈
-https://leetcode-cn.com/problems/implement-stack-using-queues/
+[力扣题目链接](https://leetcode-cn.com/problems/implement-stack-using-queues/)
使用队列实现栈的下列操作:
@@ -34,7 +34,7 @@ https://leetcode-cn.com/problems/implement-stack-using-queues/
有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!**
-刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://mp.weixin.qq.com/s/Cj6R0qu8rFA7Et9V_ZMjCA)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!
+刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://programmercarl.com/0232.用栈实现队列.html)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!
**队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。
@@ -294,66 +294,53 @@ Python:
```python
from collections import deque
-
class MyStack:
-
def __init__(self):
"""
- Python普通的Queue或SimpleQueue没有类似于peek的功能
- 也无法用索引访问,在实现top的时候较为困难。
-
- 用list可以,但是在使用pop(0)的时候时间复杂度为O(n)
- 因此这里使用双向队列,我们保证只执行popleft()和append(),因为deque可以用索引访问,可以实现和peek相似的功能
-
- in - 存所有数据
- out - 仅在pop的时候会用到
+ Initialize your data structure here.
"""
- self.queue_in = deque()
- self.queue_out = deque()
+ #使用两个队列来实现
+ self.que1 = deque()
+ self.que2 = deque()
def push(self, x: int) -> None:
"""
- 直接append即可
+ Push element x onto stack.
"""
- self.queue_in.append(x)
-
+ self.que1.append(x)
def pop(self) -> int:
"""
- 1. 首先确认不空
- 2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out
- 3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out
- 4. 交换in和out,此时out里只有一个元素
- 5. 把out中的pop出来,即是原队列的最后一个
-
- tip:这不能像栈实现队列一样,因为另一个queue也是FIFO,如果执行pop()它不能像
- stack一样从另一个pop(),所以干脆in只用来存数据,pop()的时候两个进行交换
+ Removes the element on top of the stack and returns that element.
"""
- if self.empty():
- return None
+ size = len(self.que1)
+ size -= 1#这里先减一是为了保证最后面的元素
+ while size > 0:
+ size -= 1
+ self.que2.append(self.que1.popleft())
- for i in range(len(self.queue_in) - 1):
- self.queue_out.append(self.queue_in.popleft())
-
- self.queue_in, self.queue_out = self.queue_out, self.queue_in # 交换in和out,这也是为啥in只用来存
- return self.queue_out.popleft()
+
+ result = self.que1.popleft()
+ self.que1, self.que2= self.que2, self.que1#将que2和que1交换 que1经过之前的操作应该是空了
+ #一定注意不能直接使用que1 = que2 这样que2的改变会影响que1 可以用浅拷贝
+ return result
def top(self) -> int:
"""
- 1. 首先确认不空
- 2. 我们仅有in会存放数据,所以返回第一个即可
+ Get the top element.
"""
- if self.empty():
- return None
-
- return self.queue_in[-1]
-
+ return self.que1[-1]
def empty(self) -> bool:
"""
- 因为只有in存了数据,只要判断in是不是有数即可
+ Returns whether the stack is empty.
"""
- return len(self.queue_in) == 0
+ #print(self.que1)
+ if len(self.que1) == 0:
+ return True
+ else:
+ return False
+
```
diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md
index 6eb6f301..b69cad55 100644
--- a/problems/0226.翻转二叉树.md
+++ b/problems/0226.翻转二叉树.md
@@ -9,7 +9,7 @@
# 226.翻转二叉树
-题目地址:https://leetcode-cn.com/problems/invert-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/invert-binary-tree/)
翻转一棵二叉树。
@@ -43,7 +43,7 @@
**注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果**
-**这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不行,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了**
+**这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了**
那么层序遍历可以不可以呢?**依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!**
@@ -51,7 +51,7 @@
-对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)详细讲解了。
+对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
@@ -106,8 +106,7 @@ public:
### 深度优先遍历
-
-[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
+[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
C++代码迭代法(前序遍历)
@@ -129,10 +128,10 @@ public:
}
};
```
-如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)。
+如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)。
-我们在[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
+我们在[二叉树:前中后序迭代方式的统一写法](https://programmercarl.com/二叉树的统一迭代法.html)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
C++代码如下迭代法(前序遍历)
@@ -162,7 +161,7 @@ public:
};
```
-如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
+如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。
### 广度优先遍历
@@ -188,7 +187,7 @@ public:
}
};
```
-如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
+如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
## 拓展
diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md
index 27a3de4e..0afbac6b 100644
--- a/problems/0232.用栈实现队列.md
+++ b/problems/0232.用栈实现队列.md
@@ -11,7 +11,7 @@
# 232.用栈实现队列
-https://leetcode-cn.com/problems/implement-queue-using-stacks/
+[力扣题目链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/)
使用栈实现队列的下列操作:
@@ -176,53 +176,6 @@ class MyQueue {
}
```
-个人习惯写法,使用Deque通用api:
-```java
-class MyQueue {
- // java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack
- // Deque 中的 addFirst、removeFirst、peekFirst 等方法等效于 Stack(堆栈) 中的 push、pop、peek
- Deque stIn;
- Deque stOut;
- /** Initialize your data structure here. */
- public MyQueue() {
- stIn = new ArrayDeque<>();
- stOut = new ArrayDeque<>();
- }
-
- /** Push element x to the back of queue. */
- public void push(int x) {
- stIn.addLast(x);
- }
-
- /** Removes the element from in front of queue and returns that element. */
- public int pop() {
- // 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中
- if (stOut.isEmpty()) {
- while (!stIn.isEmpty()) {
- stOut.addLast(stIn.pollLast());
- }
- }
- // 再返回 stOut 中的元素
- return stOut.pollLast();
- }
-
- /** Get the front element. */
- public int peek() {
- // 直接使用已有的pop函数
- int res = this.pop();
- // 因为pop函数弹出了元素res,所以再添加回去
- stOut.addLast(res);
- return res;
- }
-
- /** Returns whether the queue is empty. */
- public boolean empty() {
- // 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了
- // 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了
- return stIn.isEmpty() && stOut.isEmpty();
- }
-}
-```
```java
class MyQueue {
@@ -281,60 +234,48 @@ class MyQueue {
Python:
```python
+# 使用两个栈实现先进先出的队列
class MyQueue:
-
def __init__(self):
"""
- in主要负责push,out主要负责pop
+ Initialize your data structure here.
"""
- self.stack_in = []
- self.stack_out = []
-
+ self.stack1 = list()
+ self.stack2 = list()
def push(self, x: int) -> None:
"""
- 有新元素进来,就往in里面push
+ Push element x to the back of queue.
"""
- self.stack_in.append(x)
-
+ # self.stack1用于接受元素
+ self.stack1.append(x)
def pop(self) -> int:
"""
- 1. 检查如果out里面元素,则直接pop
- 2. 如果out没有元素,就把in里面的元素(除了第一个)依次pop后装进out里面
- 3. 直接把in剩下的元素pop出来,就是queue头部的
+ Removes the element from in front of queue and returns that element.
"""
- if self.empty:
- return None
-
- if self.stack_out:
- return self.stack_out.pop()
- else:
- for i in range(1, len(self.stack_in)):
- self.stack_out.append(self.stack_in.pop())
- return self.stack_in.pop()
-
+ # self.stack2用于弹出元素,如果self.stack2为[],则将self.stack1中元素全部弹出给self.stack2
+ if self.stack2 == []:
+ while self.stack1:
+ tmp = self.stack1.pop()
+ self.stack2.append(tmp)
+ return self.stack2.pop()
def peek(self) -> int:
"""
- 1. 查out有没有元素,有就把最上面的返回
- 2. 如果out没有元素,就把in最下面的返回
+ Get the front element.
"""
- if self.empty:
- return None
-
- if self.stack_out:
- return self.stack_out[-1]
- else:
- return self.stack_in[0]
-
+ if self.stack2 == []:
+ while self.stack1:
+ tmp = self.stack1.pop()
+ self.stack2.append(tmp)
+ return self.stack2[-1]
def empty(self) -> bool:
"""
- 只要in或者out有元素,说明队列不为空
+ Returns whether the queue is empty.
"""
- return not (self.stack_in or self.stack_out)
-
+ return self.stack1 == [] and self.stack2 == []
```
diff --git a/problems/0234.回文链表.md b/problems/0234.回文链表.md
index b3ad899c..04015a7f 100644
--- a/problems/0234.回文链表.md
+++ b/problems/0234.回文链表.md
@@ -9,7 +9,7 @@
# 234.回文链表
-题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/
+[力扣题目链接](https://leetcode-cn.com/problems/palindrome-linked-list/)
请判断一个链表是否为回文链表。
diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md
index fe875067..fab450ba 100644
--- a/problems/0235.二叉搜索树的最近公共祖先.md
+++ b/problems/0235.二叉搜索树的最近公共祖先.md
@@ -9,7 +9,7 @@
## 235. 二叉搜索树的最近公共祖先
-链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/)
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
@@ -38,7 +38,7 @@
## 思路
-做过[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)题目的同学应该知道,利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。
+做过[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)题目的同学应该知道,利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。
那么本题是二叉搜索树,二叉搜索树是有序的,那得好好利用一下这个特点。
@@ -48,7 +48,7 @@
理解这一点,本题就很好解了。
-和[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。
+和[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。
那么我们可以采用前序遍历(其实这里没有中节点的处理逻辑,遍历顺序无所谓了)。
@@ -105,7 +105,7 @@ if (cur->val > p->val && cur->val > q->val) {
**细心的同学会发现,在这里调用递归函数的地方,把递归函数的返回值left,直接return**。
-在[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。
+在[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。
搜索一条边的写法:
@@ -192,7 +192,7 @@ public:
## 迭代法
-对于二叉搜索树的迭代法,大家应该在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)就了解了。
+对于二叉搜索树的迭代法,大家应该在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)就了解了。
利用其有序性,迭代的方式还是比较简单的,解题思路在递归中已经分析了。
@@ -218,7 +218,7 @@ public:
## 总结
-对于二叉搜索树的最近祖先问题,其实要比[普通二叉树公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)简单的多。
+对于二叉搜索树的最近祖先问题,其实要比[普通二叉树公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)简单的多。
不用使用回溯,二叉搜索树自带方向性,可以方便的从上向下查找目标区间,遇到目标区间内的节点,直接返回。
diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md
index 0885e20f..16c235ee 100644
--- a/problems/0236.二叉树的最近公共祖先.md
+++ b/problems/0236.二叉树的最近公共祖先.md
@@ -11,7 +11,7 @@
## 236. 二叉树的最近公共祖先
-题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
@@ -79,7 +79,7 @@ if (root == q || root == p || root == NULL) return root;
值得注意的是 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。
-我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中说了 递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
+我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中说了 递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树呢?
diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md
index 3c12a985..a61e4ca8 100644
--- a/problems/0239.滑动窗口最大值.md
+++ b/problems/0239.滑动窗口最大值.md
@@ -12,7 +12,7 @@
# 239. 滑动窗口最大值
-https://leetcode-cn.com/problems/sliding-window-maximum/
+[力扣题目链接](https://leetcode-cn.com/problems/sliding-window-maximum/)
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
@@ -21,7 +21,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/
进阶:
你能在线性时间复杂度内解决此题吗?
-
+
提示:
@@ -104,7 +104,7 @@ public:
那么我们用什么数据结构来实现这个单调队列呢?
-使用deque最为合适,在文章[栈与队列:来看看栈和队列不为人知的一面](https://mp.weixin.qq.com/s/HCXfQ_Bhpi63YaX0ZRSnAQ)中,我们就提到了常用的queue在没有指定容器的情况下,deque就是默认底层容器。
+使用deque最为合适,在文章[栈与队列:来看看栈和队列不为人知的一面](https://programmercarl.com/栈与队列理论基础.html)中,我们就提到了常用的queue在没有指定容器的情况下,deque就是默认底层容器。
基于刚刚说过的单调队列pop和push的规则,代码不难实现,如下:
diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md
index b215a88a..15bf14ca 100644
--- a/problems/0242.有效的字母异位词.md
+++ b/problems/0242.有效的字母异位词.md
@@ -11,7 +11,7 @@
## 242.有效的字母异位词
-https://leetcode-cn.com/problems/valid-anagram/
+[力扣题目链接](https://leetcode-cn.com/problems/valid-anagram/)
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
@@ -35,7 +35,7 @@ https://leetcode-cn.com/problems/valid-anagram/
**数组其实就是一个简单哈希表**,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。
-如果对哈希表的理论基础关于数组,set,map不了解的话可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)
+如果对哈希表的理论基础关于数组,set,map不了解的话可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)
需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index 84315507..2984427f 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -11,7 +11,7 @@
# 257. 二叉树的所有路径
-题目地址:https://leetcode-cn.com/problems/binary-tree-paths/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-paths/)
给定一个二叉树,返回所有从根节点到叶子节点的路径。
@@ -270,7 +270,7 @@ if (cur->right) {
## 迭代法
-至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)和[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
+至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。
这里除了模拟递归需要一个栈,同时还需要一个栈来存放对应的遍历路径。
diff --git a/problems/0279.完全平方数.md b/problems/0279.完全平方数.md
index 3c0f0414..8a9c291e 100644
--- a/problems/0279.完全平方数.md
+++ b/problems/0279.完全平方数.md
@@ -9,7 +9,7 @@
## 279.完全平方数
-题目地址:https://leetcode-cn.com/problems/perfect-squares/
+[力扣题目链接](https://leetcode-cn.com/problems/perfect-squares/)
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
@@ -36,7 +36,7 @@
**我来把题目翻译一下:完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?**
-感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)就是一样一样的!
+感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)就是一样一样的!
动规五部曲分析如下:
@@ -70,7 +70,7 @@ dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
-在[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)中我们就深入探讨了这个问题,本题也是一样的,是求最小数!
+在[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)中我们就深入探讨了这个问题,本题也是一样的,是求最小数!
**所以本题外层for遍历背包,里层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的!**
@@ -146,7 +146,7 @@ public:
## 总结
-如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ),今天这道就非常简单了,一样的套路一样的味道。
+如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html),今天这道就非常简单了,一样的套路一样的味道。
但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的!
@@ -161,7 +161,6 @@ public:
Java:
```Java
class Solution {
- // 版本一,先遍历物品, 再遍历背包
public int numSquares(int n) {
int max = Integer.MAX_VALUE;
int[] dp = new int[n + 1];
@@ -171,9 +170,7 @@ class Solution {
}
//当和为0时,组合的个数为0
dp[0] = 0;
- // 遍历物品
for (int i = 1; i * i <= n; i++) {
- // 遍历背包
for (int j = i * i; j <= n; j++) {
if (dp[j - i * i] != max) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
@@ -183,28 +180,6 @@ class Solution {
return dp[n];
}
}
-
-class Solution {
- // 版本二, 先遍历背包, 再遍历物品
- public int numSquares(int n) {
- int max = Integer.MAX_VALUE;
- int[] dp = new int[n + 1];
- // 初始化
- for (int j = 0; j <= n; j++) {
- dp[j] = max;
- }
- // 当和为0时,组合的个数为0
- dp[0] = 0;
- // 遍历背包
- for (int j = 1; j <= n; j++) {
- // 遍历物品
- for (int i = 1; i * i <= j; i++) {
- dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
- }
- }
- return dp[n];
- }
-}
```
Python:
@@ -212,7 +187,7 @@ Python:
```python3
class Solution:
def numSquares(self, n: int) -> int:
- '''版本一,先遍历背包, 再遍历物品'''
+ '''版本一'''
# 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1)
@@ -226,7 +201,7 @@ class Solution:
return dp[n]
def numSquares1(self, n: int) -> int:
- '''版本二, 先遍历物品, 再遍历背包'''
+ '''版本二'''
# 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1)
@@ -242,22 +217,6 @@ class Solution:
Python3:
```python
class Solution:
- '''版本一,先遍历背包, 再遍历物品'''
- def numSquares(self, n: int) -> int:
- dp = [n] * (n + 1)
- dp[0] = 0
- # 遍历背包
- for j in range(1, n+1):
- for i in range(1, n):
- num = i ** 2
- if num > j: break
- # 遍历物品
- if j - num >= 0:
- dp[j] = min(dp[j], dp[j - num] + 1)
- return dp[n]
-
-class Solution:
- '''版本二, 先遍历物品, 再遍历背包'''
def numSquares(self, n: int) -> int:
# 初始化
# 组成和的完全平方数的最多个数,就是只用1构成
diff --git a/problems/0283.移动零.md b/problems/0283.移动零.md
index af7142fa..3909bcd5 100644
--- a/problems/0283.移动零.md
+++ b/problems/0283.移动零.md
@@ -10,7 +10,7 @@
# 283. 移动零
-题目链接:https://leetcode-cn.com/problems/move-zeroes/
+[力扣题目链接](https://leetcode-cn.com/problems/move-zeroes/)
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
@@ -26,13 +26,13 @@
# 思路
-做这道题目之前,大家可以做一做[27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)
+做这道题目之前,大家可以做一做[27.移除元素](https://programmercarl.com/0027.移除元素.html)
这道题目,使用暴力的解法,可以两层for循环,模拟数组删除元素(也就是向前覆盖)的过程。
-好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://mp.weixin.qq.com/s/PLfYLuUIGDR6xVRQ_jTrmg)。
+好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)。
-双指针法在数组移除元素中,可以达到O(n)的时间复杂度,在[27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)里已经详细讲解了,那么本题和移除元素其实是一个套路。
+双指针法在数组移除元素中,可以达到O(n)的时间复杂度,在[27.移除元素](https://programmercarl.com/0027.移除元素.html)里已经详细讲解了,那么本题和移除元素其实是一个套路。
**相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了**。
diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md
index 1161e158..b2e942ed 100644
--- a/problems/0300.最长上升子序列.md
+++ b/problems/0300.最长上升子序列.md
@@ -8,13 +8,13 @@
## 300.最长递增子序列
-题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/)
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
-
+
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
@@ -27,7 +27,7 @@
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
-
+
提示:
* 1 <= nums.length <= 2500
@@ -215,9 +215,9 @@ const lengthOfLIS = (nums) => {
1. if(nums[i]>list[len-1],此时,list中子序列长度为1到len的对应的最右端最小值不变,并新增长度为len+1的子序列,最右端的最小值为nums[i],时间复杂度O(1);
2. if(nums[i]<=list[len-1]),此时,我们可以在0到len-1范围内找到k,list[k]为>=nums[i]的最小值,由于list单调递增,所以我们可以使用二分搜索在O(logn)的时间复杂度内找到k。
- 1. 对于0<=jnums[i];
+ 1. 对于0<=jnums[i];
3. 综上,算法时间复杂度为O(nlogn),空间复杂度为O(n),需要O(n)的空间保存list。
diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md
index 3b1b6500..59178c64 100644
--- a/problems/0309.最佳买卖股票时机含冷冻期.md
+++ b/problems/0309.最佳买卖股票时机含冷冻期.md
@@ -8,9 +8,11 @@
## 309.最佳买卖股票时机含冷冻期
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
-给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
+[https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
+
+给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
@@ -25,12 +27,12 @@
## 思路
-> 之前我们在[动态规划:最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/IgC0iWWCDpYL9ZbTHGHgfw)讲过一次这道题目,讲解的过程感觉不是很严谨,和录友们也聊过这个问题,本着对大家负责的态度,有问题的地方我都会及时纠正,所以重新发文讲解一下。
+> 之前我们在[动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)讲过一次这道题目,讲解的过程感觉不是很严谨,和录友们也聊过这个问题,本着对大家负责的态度,有问题的地方我都会及时纠正,所以重新发文讲解一下。
-相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题加上了一个冷冻期
+相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期
-在[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。
+在[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。
动规五部曲,分析如下:
diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md
index 758bd5b8..cdc5027c 100644
--- a/problems/0322.零钱兑换.md
+++ b/problems/0322.零钱兑换.md
@@ -9,7 +9,7 @@
## 322. 零钱兑换
-题目链接:https://leetcode-cn.com/problems/coin-change/
+[力扣题目链接](https://leetcode-cn.com/problems/coin-change/)
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
@@ -44,7 +44,7 @@
## 思路
-在[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中我们已经兑换一次零钱了,这次又要兑换,套路不一样!
+在[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经兑换一次零钱了,这次又要兑换,套路不一样!
题目中说每种硬币的数量是无限的,可以看出是典型的完全背包问题。
@@ -91,7 +91,7 @@ dp[0] = 0;
**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
-在动态规划专题我们讲过了求组合数是[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ),求排列数是[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)。
+在动态规划专题我们讲过了求组合数是[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html),求排列数是[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)。
**所以本题的两个for循环的关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以的!**
@@ -166,7 +166,7 @@ public:
那么这篇文章就把遍历顺序分析的清清楚楚。
-[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中求的是组合数,[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)中求的是排列数。
+[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中求的是组合数,[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)中求的是排列数。
**而本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!**
diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md
index 8a28899b..13ad9e35 100644
--- a/problems/0332.重新安排行程.md
+++ b/problems/0332.重新安排行程.md
@@ -11,7 +11,7 @@
## 332.重新安排行程
-题目地址:https://leetcode-cn.com/problems/reconstruct-itinerary/
+[力扣题目链接](https://leetcode-cn.com/problems/reconstruct-itinerary/)
给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。
@@ -20,7 +20,7 @@
* 所有的机场都用三个大写字母表示(机场代码)。
* 假定所有机票至少存在一种合理的行程。
* 所有的机票必须都用一次 且 只能用一次。
-
+
示例 1:
输入:[["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
@@ -36,7 +36,7 @@
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
-这道题目还是很难的,之前我们用回溯法解决了如下问题:[组合问题](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[分割问题](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA),[子集问题](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA),[排列问题](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw)。
+这道题目还是很难的,之前我们用回溯法解决了如下问题:[组合问题](https://programmercarl.com/0077.组合.html),[分割问题](https://programmercarl.com/0093.复原IP地址.html),[子集问题](https://programmercarl.com/0078.子集.html),[排列问题](https://programmercarl.com/0046.全排列.html)。
直觉上来看 这道题和回溯法没有什么关系,更像是图论中的深度优先搜索。
@@ -69,7 +69,7 @@
一个机场映射多个机场,机场之间要靠字母序排列,一个机场映射多个机场,可以使用std::unordered_map,如果让多个机场之间再有顺序的话,就是用std::map 或者std::multimap 或者 std::multiset。
-如果对map 和 set 的实现机制不太了解,也不清楚为什么 map、multimap就是有序的同学,可以看这篇文章[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)。
+如果对map 和 set 的实现机制不太了解,也不清楚为什么 map、multimap就是有序的同学,可以看这篇文章[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。
这样存放映射关系可以定义为 `unordered_map> targets` 或者 `unordered_map> targets`。
@@ -140,7 +140,7 @@ bool backtracking(int ticketNum, vector& result) {

-所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)详细介绍过。
+所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)详细介绍过。
当然本题的targets和result都需要初始化,代码如下:
```
@@ -164,7 +164,7 @@ if (result.size() == ticketNum + 1) {
}
```
-已经看习惯回溯法代码的同学,到叶子节点了习惯性的想要收集结果,但发现并不需要,本题的result相当于 [回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中的path,也就是本题的result就是记录路径的(就一条),在如下单层搜索的逻辑中result就添加元素了。
+已经看习惯回溯法代码的同学,到叶子节点了习惯性的想要收集结果,但发现并不需要,本题的result相当于 [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中的path,也就是本题的result就是记录路径的(就一条),在如下单层搜索的逻辑中result就添加元素了。
* 单层搜索的逻辑
diff --git a/problems/0337.打家劫舍III.md b/problems/0337.打家劫舍III.md
index 44e60fb3..2a69ac56 100644
--- a/problems/0337.打家劫舍III.md
+++ b/problems/0337.打家劫舍III.md
@@ -9,7 +9,7 @@
## 337.打家劫舍 III
-题目链接:https://leetcode-cn.com/problems/house-robber-iii/
+[力扣题目链接](https://leetcode-cn.com/problems/house-robber-iii/)
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
@@ -19,7 +19,7 @@
## 思路
-这道题目和 [198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw),[213.打家劫舍II](https://mp.weixin.qq.com/s/kKPx4HpH3RArbRcxAVHbeQ)也是如出一辙,只不过这个换成了树。
+这道题目和 [198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html),[213.打家劫舍II](https://programmercarl.com/0213.打家劫舍II.html)也是如出一辙,只不过这个换成了树。
如果对树的遍历不够熟悉的话,那本题就有难度了。
@@ -210,7 +210,7 @@ public:
只不过平时我们习惯了在一维数组或者二维数组上推导公式,一下子换成了树,就需要对树的遍历方式足够了解!
-大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://mp.weixin.qq.com/s/kCxlLLjWKaE6nifHC3UL2Q),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈
+大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://programmercarl.com/0968.监控二叉树.html),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈
“树形贪心”词汇从此诞生,来自「代码随想录」
diff --git a/problems/0343.整数拆分.md b/problems/0343.整数拆分.md
index 03b6f0fc..c11210fc 100644
--- a/problems/0343.整数拆分.md
+++ b/problems/0343.整数拆分.md
@@ -8,14 +8,15 @@
## 343. 整数拆分
-题目链接:https://leetcode-cn.com/problems/integer-break/
+[力扣题目链接](https://leetcode-cn.com/problems/integer-break/)
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
-解释: 2 = 1 + 1, 1 × 1 = 1。
+
+\解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md
index 8925d0e1..226d5b51 100644
--- a/problems/0344.反转字符串.md
+++ b/problems/0344.反转字符串.md
@@ -12,7 +12,7 @@
# 344.反转字符串
-https://leetcode-cn.com/problems/reverse-string/
+[力扣题目链接](https://leetcode-cn.com/problems/reverse-string/)
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
@@ -55,7 +55,7 @@ https://leetcode-cn.com/problems/reverse-string/
接下来再来讲一下如何解决反转字符串的问题。
-大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)。
+大家应该还记得,我们已经讲过了[206.反转链表](https://programmercarl.com/0206.翻转链表.html)。
在反转链表中,使用了双指针的方法。
@@ -63,7 +63,7 @@ https://leetcode-cn.com/problems/reverse-string/
因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。
-如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw),[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)。
+如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html),[必须掌握的数组理论知识](https://programmercarl.com/数组理论基础.html)。
对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
@@ -162,14 +162,21 @@ class Solution:
Do not return anything, modify s in-place instead.
"""
left, right = 0, len(s) - 1
-
- # 该方法已经不需要判断奇偶数,经测试后时间空间复杂度比用 for i in range(right//2)更低
- # 推荐该写法,更加通俗易懂
- while left < right:
+ while(left < right):
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
-
+
+# 下面的写法更加简洁,但是都是同样的算法
+# class Solution:
+# def reverseString(self, s: List[str]) -> None:
+# """
+# Do not return anything, modify s in-place instead.
+# """
+ # 不需要判别是偶数个还是奇数个序列,因为奇数个的时候,中间那个不需要交换就可
+# for i in range(len(s)//2):
+# s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
+# return s
```
Go:
diff --git a/problems/0347.前K个高频元素.md b/problems/0347.前K个高频元素.md
index 680de3bd..54be5cc4 100644
--- a/problems/0347.前K个高频元素.md
+++ b/problems/0347.前K个高频元素.md
@@ -13,7 +13,7 @@
# 347.前 K 个高频元素
-https://leetcode-cn.com/problems/top-k-frequent-elements/
+[力扣题目链接](https://leetcode-cn.com/problems/top-k-frequent-elements/)
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md
index 62abf639..49fe926b 100644
--- a/problems/0349.两个数组的交集.md
+++ b/problems/0349.两个数组的交集.md
@@ -14,7 +14,7 @@
## 349. 两个数组的交集
-https://leetcode-cn.com/problems/intersection-of-two-arrays/
+[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/)
题意:给定两个数组,编写一个函数来计算它们的交集。
@@ -32,7 +32,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
-那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)
+那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)
但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。**
@@ -143,26 +143,6 @@ func intersection(nums1 []int, nums2 []int) []int {
return res
}
```
-```golang
-//优化版,利用set,减少count统计
-func intersection(nums1 []int, nums2 []int) []int {
- set:=make(map[int]struct{},0)
- res:=make([]int,0)
- for _,v:=range nums1{
- if _,ok:=set[v];!ok{
- set[v]=struct{}{}
- }
- }
- for _,v:=range nums2{
- //如果存在于上一个数组中,则加入结果集,并清空该set值
- if _,ok:=set[v];ok{
- res=append(res,v)
- delete(set, v)
- }
- }
- return res
-}
-```
javaScript:
diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md
index 0ccc405a..75965c37 100644
--- a/problems/0376.摆动序列.md
+++ b/problems/0376.摆动序列.md
@@ -7,11 +7,11 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-> 本周讲解了[贪心理论基础](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),以及第一道贪心的题目:[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
+> 本周讲解了[贪心理论基础](https://programmercarl.com/贪心算法理论基础.html),以及第一道贪心的题目:[贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
## 376. 摆动序列
-题目链接:https://leetcode-cn.com/problems/wiggle-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/wiggle-subsequence/)
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md
index 3f735727..f062a897 100644
--- a/problems/0377.组合总和Ⅳ.md
+++ b/problems/0377.组合总和Ⅳ.md
@@ -9,7 +9,7 @@
## 377. 组合总和 Ⅳ
-题目链接:https://leetcode-cn.com/problems/combination-sum-iv/
+[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-iv/)
难度:中等
@@ -43,7 +43,7 @@ target = 4
排列强调顺序,(1,5)和(5,1)是两个不同的排列。
-大家在公众号里学习回溯算法专题的时候,一定做过这两道题目[回溯算法:39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)和[回溯算法:40.组合总和II](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)会感觉这两题和本题很像!
+大家在公众号里学习回溯算法专题的时候,一定做过这两道题目[回溯算法:39.组合总和](https://programmercarl.com/0039.组合总和.html)和[回溯算法:40.组合总和II](https://programmercarl.com/0040.组合总和II.html)会感觉这两题和本题很像!
但其本质是本题求的是排列总和,而且仅仅是求排列总和的个数,并不是把所有的排列都列出来。
@@ -61,7 +61,7 @@ dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导
因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。
-在[动态规划:494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) 和 [动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中我们已经讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
+在[动态规划:494.目标和](https://programmercarl.com/0494.目标和.html) 和 [动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
本题也一样。
@@ -87,7 +87,7 @@ dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导
本题要求的是排列,那么这个for循环嵌套的顺序可以有说法了。
-在[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) 中就已经讲过了。
+在[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) 中就已经讲过了。
**如果求组合数就是外层for循环遍历物品,内层for遍历背包**。
@@ -134,7 +134,7 @@ C++测试用例有超过两个树相加超过int的数据,所以需要在if里
**求装满背包有几种方法,递归公式都是一样的,没有什么差别,但关键在于遍历顺序!**
-本题与[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)就是一个鲜明的对比,一个是求排列,一个是求组合,遍历顺序完全不同。
+本题与[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)就是一个鲜明的对比,一个是求排列,一个是求组合,遍历顺序完全不同。
如果对遍历顺序没有深度理解的话,做这种完全背包的题目会很懵逼,即使题目刷过了可能也不太清楚具体是怎么过的。
diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md
index d4b73848..64503cef 100644
--- a/problems/0383.赎金信.md
+++ b/problems/0383.赎金信.md
@@ -12,7 +12,7 @@
# 383. 赎金信
-https://leetcode-cn.com/problems/ransom-note/
+[力扣题目链接](https://leetcode-cn.com/problems/ransom-note/)
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
@@ -28,7 +28,7 @@ canConstruct("aa", "aab") -> true
## 思路
-这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
+这道题目和[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)很像,[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,但是这里需要注意两点。
diff --git a/problems/0392.判断子序列.md b/problems/0392.判断子序列.md
index bcf3462b..54c16489 100644
--- a/problems/0392.判断子序列.md
+++ b/problems/0392.判断子序列.md
@@ -9,7 +9,7 @@
## 392.判断子序列
-题目链接:https://leetcode-cn.com/problems/is-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/is-subsequence/)
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md
index 84ec2310..2b627b6c 100644
--- a/problems/0404.左叶子之和.md
+++ b/problems/0404.左叶子之和.md
@@ -9,7 +9,7 @@
# 404.左叶子之和
-题目地址:https://leetcode-cn.com/problems/sum-of-left-leaves/
+[力扣题目链接](https://leetcode-cn.com/problems/sum-of-left-leaves/)
计算给定二叉树的所有左叶子之和。
@@ -119,7 +119,7 @@ public:
## 迭代法
-本题迭代法使用前中后序都是可以的,只要把左叶子节点统计出来,就可以了,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)和[二叉树:迭代法统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)中的写法,可以写出一个前序遍历的迭代法。
+本题迭代法使用前中后序都是可以的,只要把左叶子节点统计出来,就可以了,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:迭代法统一写法](https://programmercarl.com/二叉树的统一迭代法.html)中的写法,可以写出一个前序遍历的迭代法。
判断条件都是一样的,代码如下:
@@ -326,7 +326,7 @@ var sumOfLeftLeaves = function(root) {
}
return nodesSum(root);
};
-```
+```
**迭代法**
```javascript
diff --git a/problems/0406.根据身高重建队列.md b/problems/0406.根据身高重建队列.md
index e9b9a738..6d8f703b 100644
--- a/problems/0406.根据身高重建队列.md
+++ b/problems/0406.根据身高重建队列.md
@@ -9,7 +9,7 @@
## 406.根据身高重建队列
-题目链接:https://leetcode-cn.com/problems/queue-reconstruction-by-height/
+[力扣题目链接](https://leetcode-cn.com/problems/queue-reconstruction-by-height/)
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
@@ -43,9 +43,9 @@
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后在按照另一个维度重新排列。
-其实如果大家认真做了[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ),就会发现和此题有点点的像。
+其实如果大家认真做了[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html),就会发现和此题有点点的像。
-在[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
+在[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
**如果两个维度一起考虑一定会顾此失彼**。
@@ -76,11 +76,11 @@
一些同学可能也会疑惑,你怎么知道局部最优就可以推出全局最优呢? 有数学证明么?
-在贪心系列开篇词[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中,我已经讲过了这个问题了。
+在贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中,我已经讲过了这个问题了。
刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心,至于严格的数学证明,就不在讨论范围内了。
-如果没有读过[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)的同学建议读一下,相信对贪心就有初步的了解了。
+如果没有读过[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)的同学建议读一下,相信对贪心就有初步的了解了。
回归本题,整个插入过程如下:
@@ -157,15 +157,15 @@ public:
大家可以把两个版本的代码提交一下试试,就可以发现其差别了!
-关于本题使用数组还是使用链表的性能差异,我在[贪心算法:根据身高重建队列(续集)](https://mp.weixin.qq.com/s/K-pRN0lzR-iZhoi-1FgbSQ)中详细讲解了一波
+关于本题使用数组还是使用链表的性能差异,我在[贪心算法:根据身高重建队列(续集)](https://programmercarl.com/根据身高重建队列(vector原理讲解).html)中详细讲解了一波
## 总结
-关于出现两个维度一起考虑的情况,我们已经做过两道题目了,另一道就是[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)。
+关于出现两个维度一起考虑的情况,我们已经做过两道题目了,另一道就是[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)。
**其技巧都是确定一边然后贪心另一边,两边一起考虑,就会顾此失彼**。
-这道题目可以说比[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)难不少,其贪心的策略也是比较巧妙。
+这道题目可以说比[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)难不少,其贪心的策略也是比较巧妙。
最后我给出了两个版本的代码,可以明显看是使用C++中的list(底层链表实现)比vector(数组)效率高得多。
diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md
index 0f1f094a..c8a5beea 100644
--- a/problems/0416.分割等和子集.md
+++ b/problems/0416.分割等和子集.md
@@ -8,7 +8,7 @@
## 416. 分割等和子集
-题目链接:https://leetcode-cn.com/problems/partition-equal-subset-sum/
+[力扣题目链接](https://leetcode-cn.com/problems/partition-equal-subset-sum/)
题目难易:中等
@@ -22,7 +22,7 @@
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
-
+
示例 2:
输入: [1, 2, 3, 5]
输出: false
@@ -47,8 +47,8 @@
如果对01背包不够了解,建议仔细看完如下两篇:
-* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)
-* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)
+* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)
+* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)
## 01背包问题
@@ -114,7 +114,7 @@ vector dp(10001, 0);
4. 确定遍历顺序
-在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
+在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
代码如下:
diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md
index f5da71c7..ae037f17 100644
--- a/problems/0435.无重叠区间.md
+++ b/problems/0435.无重叠区间.md
@@ -9,7 +9,7 @@
## 435. 无重叠区间
-题目链接:https://leetcode-cn.com/problems/non-overlapping-intervals/
+[力扣题目链接](https://leetcode-cn.com/problems/non-overlapping-intervals/)
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
@@ -122,9 +122,9 @@ public:
## 补充
-本题其实和[452.用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)非常像,弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号(认为[0,1][1,2]不是相邻区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。
+本题其实和[452.用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)非常像,弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号(认为[0,1][1,2]不是相邻区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。
-把[452.用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)代码稍做修改,就可以AC本题。
+把[452.用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)代码稍做修改,就可以AC本题。
```CPP
class Solution {
diff --git a/problems/0450.删除二叉搜索树中的节点.md b/problems/0450.删除二叉搜索树中的节点.md
index 96c49468..0c8ea9ff 100644
--- a/problems/0450.删除二叉搜索树中的节点.md
+++ b/problems/0450.删除二叉搜索树中的节点.md
@@ -11,7 +11,7 @@
## 450.删除二叉搜索树中的节点
-题目链接: https://leetcode-cn.com/problems/delete-node-in-a-bst/
+[力扣题目链接]( https://leetcode-cn.com/problems/delete-node-in-a-bst/)
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
@@ -35,7 +35,7 @@
* 确定递归函数参数以及返回值
-说道递归函数的返回值,在[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。
+说道递归函数的返回值,在[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。
代码如下:
diff --git a/problems/0452.用最少数量的箭引爆气球.md b/problems/0452.用最少数量的箭引爆气球.md
index 589105b2..7b8130f0 100644
--- a/problems/0452.用最少数量的箭引爆气球.md
+++ b/problems/0452.用最少数量的箭引爆气球.md
@@ -9,7 +9,7 @@
## 452. 用最少数量的箭引爆气球
-题目链接:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/
+[力扣题目链接](https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/)
在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。
diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md
index eafee43e..7bb24e59 100644
--- a/problems/0454.四数相加II.md
+++ b/problems/0454.四数相加II.md
@@ -11,8 +11,7 @@
# 第454题.四数相加II
-
-https://leetcode-cn.com/problems/4sum-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/4sum-ii/)
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
@@ -35,9 +34,9 @@ D = [ 0, 2]
# 思路
-本题咋眼一看好像和[0015.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A),[0018.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)差不多,其实差很多。
+本题咋眼一看好像和[0015.三数之和](https://programmercarl.com/0015.三数之和.html),[0018.四数之和](https://programmercarl.com/0018.四数之和.html)差不多,其实差很多。
-**本题是使用哈希法的经典题目,而[0015.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A),[0018.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)并不合适使用哈希法**,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。
+**本题是使用哈希法的经典题目,而[0015.三数之和](https://programmercarl.com/0015.三数之和.html),[0018.四数之和](https://programmercarl.com/0018.四数之和.html)并不合适使用哈希法**,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。
**而这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于题目18. 四数之和,题目15.三数之和,还是简单了不少!**
diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md
index 19268942..b6fa4a98 100644
--- a/problems/0455.分发饼干.md
+++ b/problems/0455.分发饼干.md
@@ -9,7 +9,7 @@
## 455.分发饼干
-题目链接:https://leetcode-cn.com/problems/assign-cookies/
+[力扣题目链接](https://leetcode-cn.com/problems/assign-cookies/)
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
@@ -165,7 +165,7 @@ func findContentChildren(g []int, s []int) int {
Javascript:
-```Javascript
+```Javascript
var findContentChildren = function(g, s) {
g = g.sort((a, b) => a - b)
diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md
index 3b735942..7d8a7286 100644
--- a/problems/0459.重复的子字符串.md
+++ b/problems/0459.重复的子字符串.md
@@ -13,7 +13,7 @@
# 459.重复的子字符串
-https://leetcode-cn.com/problems/repeated-substring-pattern/
+[力扣题目链接](https://leetcode-cn.com/problems/repeated-substring-pattern/)
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
@@ -41,11 +41,11 @@ https://leetcode-cn.com/problems/repeated-substring-pattern/
* [帮你把KMP算法学个通透!(求next数组代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx)
-我们在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)里提到了,在一个串中查找是否出现过另一个串,这是KMP的看家本领。
+我们在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)里提到了,在一个串中查找是否出现过另一个串,这是KMP的看家本领。
那么寻找重复子串怎么也涉及到KMP算法了呢?
-这里就要说一说next数组了,next 数组记录的就是最长相同前后缀( [字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀), 如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。
+这里就要说一说next数组了,next 数组记录的就是最长相同前后缀( [字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀), 如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。
最长相等前后缀的长度为:next[len - 1] + 1。
@@ -137,11 +137,11 @@ public:
# 拓展
-在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)中讲解KMP算法的基础理论,给出next数组究竟是如何来了,前缀表又是怎么回事,为什么要选择前缀表。
+在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)中讲解KMP算法的基础理论,给出next数组究竟是如何来了,前缀表又是怎么回事,为什么要选择前缀表。
讲解一道KMP的经典题目,力扣:28. 实现 strStr(),判断文本串里是否出现过模式串,这里涉及到构造next数组的代码实现,以及使用next数组完成模式串与文本串的匹配过程。
-后来很多同学反馈说:搞不懂前后缀,什么又是最长相同前后缀(最长公共前后缀我认为这个用词不准确),以及为什么前缀表要统一减一(右移)呢,不减一行不行?针对这些问题,我在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)给出了详细的讲解。
+后来很多同学反馈说:搞不懂前后缀,什么又是最长相同前后缀(最长公共前后缀我认为这个用词不准确),以及为什么前缀表要统一减一(右移)呢,不减一行不行?针对这些问题,我在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)给出了详细的讲解。
## 其他语言版本
diff --git a/problems/0463.岛屿的周长.md b/problems/0463.岛屿的周长.md
index 15255d3e..18654758 100644
--- a/problems/0463.岛屿的周长.md
+++ b/problems/0463.岛屿的周长.md
@@ -1,6 +1,6 @@
## 题目链接
-https://leetcode-cn.com/problems/island-perimeter/
+[力扣题目链接](https://leetcode-cn.com/problems/island-perimeter/)
## 思路
diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md
index 90d1227a..48dae287 100644
--- a/problems/0474.一和零.md
+++ b/problems/0474.一和零.md
@@ -9,7 +9,7 @@
## 474.一和零
-题目链接:https://leetcode-cn.com/problems/ones-and-zeroes/
+[力扣题目链接](https://leetcode-cn.com/problems/ones-and-zeroes/)
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
@@ -84,13 +84,13 @@ dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
3. dp数组如何初始化
-在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中已经讲解了,01背包的dp数组初始化为0就可以。
+在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中已经讲解了,01背包的dp数组初始化为0就可以。
因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
4. 确定遍历顺序
-在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中,我们讲到了01背包为什么一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
+在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中,我们讲到了01背包为什么一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
那么本题也是,物品就是strs里的字符串,背包容量就是题目描述中的m和n。
diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md
index ed712f34..8eeb434d 100644
--- a/problems/0491.递增子序列.md
+++ b/problems/0491.递增子序列.md
@@ -11,7 +11,7 @@
## 491.递增子序列
-题目链接:https://leetcode-cn.com/problems/increasing-subsequences/
+[力扣题目链接](https://leetcode-cn.com/problems/increasing-subsequences/)
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
@@ -33,11 +33,11 @@
这个递增子序列比较像是取有序的子集。而且本题也要求不能有相同的递增子序列。
-这又是子集,又是去重,是不是不由自主的想起了刚刚讲过的[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)。
+这又是子集,又是去重,是不是不由自主的想起了刚刚讲过的[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)。
就是因为太像了,更要注意差别所在,要不就掉坑里了!
-在[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中我们是通过排序,再加一个标记数组来达到去重的目的。
+在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中我们是通过排序,再加一个标记数组来达到去重的目的。
而本题求自增子序列,是不能对原数组经行排序的,排完序的数组都是自增子序列了。
@@ -66,7 +66,7 @@ void backtracking(vector& nums, int startIndex)
* 终止条件
-本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以和[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)一样,可以不加终止条件,startIndex每次都会加1,并不会无限递归。
+本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)一样,可以不加终止条件,startIndex每次都会加1,并不会无限递归。
但本题收集结果有所不同,题目要求递增子序列大小至少为2,所以代码如下:
@@ -184,7 +184,7 @@ public:
这份代码在leetcode上提交,要比版本一耗时要好的多。
-**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://mp.weixin.qq.com/s/1s91yXtarL-PkX07BfnwLg)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如何数值范围小的话能用数组尽量用数组**。
+**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://programmercarl.com/哈希表总结.html)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如何数值范围小的话能用数组尽量用数组**。
@@ -192,7 +192,7 @@ public:
本题题解清一色都说是深度优先搜索,但我更倾向于说它用回溯法,而且本题我也是完全使用回溯法的逻辑来分析的。
-相信大家在本题中处处都能看到是[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)的身影,但处处又都是陷阱。
+相信大家在本题中处处都能看到是[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)的身影,但处处又都是陷阱。
**对于养成思维定式或者套模板套嗨了的同学,这道题起到了很好的警醒作用。更重要的是拓展了大家的思路!**
diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md
index d9a30529..63ace2a7 100644
--- a/problems/0494.目标和.md
+++ b/problems/0494.目标和.md
@@ -9,7 +9,7 @@
## 494. 目标和
-题目链接:https://leetcode-cn.com/problems/target-sum/
+[力扣题目链接](https://leetcode-cn.com/problems/target-sum/)
难度:中等
@@ -19,15 +19,15 @@
示例:
-输入:nums: [1, 1, 1, 1, 1], S: 3
-输出:5
+输入:nums: [1, 1, 1, 1, 1], S: 3
+输出:5
-解释:
--1+1+1+1+1 = 3
-+1-1+1+1+1 = 3
-+1+1-1+1+1 = 3
-+1+1+1-1+1 = 3
-+1+1+1+1-1 = 3
+解释:
+-1+1+1+1+1 = 3
++1-1+1+1+1 = 3
++1+1-1+1+1 = 3
++1+1+1-1+1 = 3
++1+1+1+1-1 = 3
一共有5种方法让最终目标和为3。
@@ -39,7 +39,7 @@
## 思路
-如果跟着「代码随想录」一起学过[回溯算法系列](https://mp.weixin.qq.com/s/r73thpBnK1tXndFDtlsdCQ)的录友,看到这道题,应该有一种直觉,就是感觉好像回溯法可以爆搜出来。
+如果跟着「代码随想录」一起学过[回溯算法系列](https://programmercarl.com/回溯总结.html)的录友,看到这道题,应该有一种直觉,就是感觉好像回溯法可以爆搜出来。
事实确实如此,下面我也会给出相应的代码,只不过会超时,哈哈。
@@ -59,7 +59,7 @@ target是固定的,sum是固定的,left就可以求出来。
## 回溯算法
-在回溯算法系列中,一起学过这道题目[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)的录友应该感觉很熟悉,这不就是组合总和问题么?
+在回溯算法系列中,一起学过这道题目[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)的录友应该感觉很熟悉,这不就是组合总和问题么?
此时可以套组合总和的回溯法代码,几乎不用改动。
@@ -144,7 +144,7 @@ dp[j] 表示:填满j(包括j)这么大容积的包,有dp[i]种方法
其实也可以使用二维dp数组来求解本题,dp[i][j]:使用 下标为[0, i]的nums[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种方法。
-下面我都是统一使用一维数组进行讲解, 二维降为一维(滚动数组),其实就是上一层拷贝下来,这个我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)也有介绍。
+下面我都是统一使用一维数组进行讲解, 二维降为一维(滚动数组),其实就是上一层拷贝下来,这个我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)也有介绍。
2. 确定递推公式
@@ -179,7 +179,7 @@ dp[j]其他下标对应的数值应该初始化为0,从递归公式也可以
4. 确定遍历顺序
-在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中,我们讲过对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。
+在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中,我们讲过对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。
5. 举例推导dp数组
@@ -202,7 +202,6 @@ public:
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (S > sum) return 0; // 此时没有方案
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
- if (S + sum < 0) return 0; // 以确保bagSize为正数
int bagSize = (S + sum) / 2;
vector dp(bagSize + 1, 0);
dp[0] = 1;
@@ -222,9 +221,9 @@ public:
## 总结
-此时 大家应该不仅想起,我们之前讲过的[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)是不是应该也可以用dp来做啊?
+此时 大家应该不仅想起,我们之前讲过的[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)是不是应该也可以用dp来做啊?
-是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)要求的是把所有组合列出来,还是要使用回溯法爆搜的。
+是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)要求的是把所有组合列出来,还是要使用回溯法爆搜的。
本题还是有点难度,大家也可以记住,在求装满背包有几种方法的情况下,递推公式一般为:
@@ -313,7 +312,7 @@ Javascript:
const findTargetSumWays = (nums, target) => {
const sum = nums.reduce((a, b) => a+b);
-
+
if(target > sum) {
return 0;
}
diff --git a/problems/0496.下一个更大元素I.md b/problems/0496.下一个更大元素I.md
index 589ee8ad..95aca60b 100644
--- a/problems/0496.下一个更大元素I.md
+++ b/problems/0496.下一个更大元素I.md
@@ -1,7 +1,7 @@
# 496.下一个更大元素 I
-题目链接:https://leetcode-cn.com/problems/next-greater-element-i/
+[力扣题目链接](https://leetcode-cn.com/problems/next-greater-element-i/)
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
@@ -24,7 +24,7 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出-1 。
-
+
提示:
* 1 <= nums1.length <= nums2.length <= 1000
@@ -34,13 +34,13 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
# 思路
-做本题之前,建议先做一下[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)
+做本题之前,建议先做一下[739. 每日温度](https://programmercarl.com/0739.每日温度.html)
-在[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)中是求每个元素下一个比当前元素大的元素的位置。
+在[739. 每日温度](https://programmercarl.com/0739.每日温度.html)中是求每个元素下一个比当前元素大的元素的位置。
本题则是说nums1 是 nums2的子集,找nums1中的元素在nums2中下一个比当前元素大的元素。
-看上去和[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q) 就如出一辙了。
+看上去和[739. 每日温度](https://programmercarl.com/0739.每日温度.html) 就如出一辙了。
几乎是一样的,但是这么绕了一下,其实还上升了一点难度。
@@ -60,7 +60,7 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。
-C++中,当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的。我在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中也做了详细的解释。
+C++中,当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的。我在[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中也做了详细的解释。
那么预处理代码如下:
diff --git a/problems/0501.二叉搜索树中的众数.md b/problems/0501.二叉搜索树中的众数.md
index f29fd08a..4221e285 100644
--- a/problems/0501.二叉搜索树中的众数.md
+++ b/problems/0501.二叉搜索树中的众数.md
@@ -11,7 +11,7 @@
## 501.二叉搜索树中的众数
-题目地址:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/
+[力扣题目链接](https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/)
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
@@ -161,7 +161,7 @@ void searchBST(TreeNode* cur) {
这就考察对树的操作了。
-在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)中我们就使用了pre指针和cur指针的技巧,这次又用上了。
+在[二叉树:搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)中我们就使用了pre指针和cur指针的技巧,这次又用上了。
弄一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
@@ -272,8 +272,8 @@ public:
二叉树前中后序转迭代,传送门:
-* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)
-* [二叉树:前中后序统一风格的迭代方式](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
+* [二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)
+* [二叉树:前中后序统一风格的迭代方式](https://programmercarl.com/二叉树的统一迭代法.html)
下面我给出其中的一种中序遍历的迭代法,其中间处理逻辑一点都没有变(我从递归法直接粘过来的代码,连注释都没改,哈哈)
diff --git a/problems/0503.下一个更大元素II.md b/problems/0503.下一个更大元素II.md
index 9f38d80d..4e088ed4 100644
--- a/problems/0503.下一个更大元素II.md
+++ b/problems/0503.下一个更大元素II.md
@@ -1,7 +1,7 @@
# 503.下一个更大元素II
-链接:https://leetcode-cn.com/problems/next-greater-element-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/next-greater-element-ii/)
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
@@ -14,13 +14,13 @@
# 思路
-做本题之前建议先做[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q) 和 [496.下一个更大元素 I](https://mp.weixin.qq.com/s/U0O6XkFOe-RMXthPS16sWQ)。
+做本题之前建议先做[739. 每日温度](https://programmercarl.com/0739.每日温度.html) 和 [496.下一个更大元素 I](https://programmercarl.com/0496.下一个更大元素I.html)。
-这道题和[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)也几乎如出一辙。
+这道题和[739. 每日温度](https://programmercarl.com/0739.每日温度.html)也几乎如出一辙。
不同的时候本题要循环数组了。
-关于单调栈的讲解我在题解[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)中已经详细讲解了。
+关于单调栈的讲解我在题解[739. 每日温度](https://programmercarl.com/0739.每日温度.html)中已经详细讲解了。
本篇我侧重与说一说,如何处理循环数组。
diff --git a/problems/0509.斐波那契数.md b/problems/0509.斐波那契数.md
index 3b3d5056..293e2323 100644
--- a/problems/0509.斐波那契数.md
+++ b/problems/0509.斐波那契数.md
@@ -8,7 +8,7 @@
## 509. 斐波那契数
-题目地址:https://leetcode-cn.com/problems/fibonacci-number/
+[力扣题目链接](https://leetcode-cn.com/problems/fibonacci-number/)
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
@@ -29,7 +29,7 @@ F(n) = F(n - 1) + F(n - 2),其中 n > 1
输入:4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
-
+
提示:
* 0 <= n <= 30
@@ -47,7 +47,7 @@ F(n) = F(n - 1) + F(n - 2),其中 n > 1
对于动规,如果没有方法论的话,可能简单题目可以顺手一写就过,难一点就不知道如何下手了。
-所以我总结的动规五部曲,是要用来贯穿整个动态规划系列的,就像之前讲过[二叉树系列的递归三部曲](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ),[回溯法系列的回溯三部曲](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)一样。后面慢慢大家就会体会到,动规五部曲方法的重要性。
+所以我总结的动规五部曲,是要用来贯穿整个动态规划系列的,就像之前讲过[二叉树系列的递归三部曲](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html),[回溯法系列的回溯三部曲](https://programmercarl.com/回溯算法理论基础.html)一样。后面慢慢大家就会体会到,动规五部曲方法的重要性。
### 动态规划
@@ -150,14 +150,14 @@ public:
* 时间复杂度:O(2^n)
* 空间复杂度:O(n) 算上了编程语言中实现递归的系统栈所占空间
-这个递归的时间复杂度大家画一下树形图就知道了,如果不清晰的同学,可以看这篇:[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ)
+这个递归的时间复杂度大家画一下树形图就知道了,如果不清晰的同学,可以看这篇:[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html)
# 总结
斐波那契数列这道题目是非常基础的题目,我在后面的动态规划的讲解中将会多次提到斐波那契数列!
-这里我严格按照[关于动态规划,你该了解这些!](https://leetcode-cn.com/circle/article/tNuNnM/)中的动规五部曲来分析了这道题目,一些分析步骤可能同学感觉没有必要搞的这么复杂,代码其实上来就可以撸出来。
+这里我严格按照[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)中的动规五部曲来分析了这道题目,一些分析步骤可能同学感觉没有必要搞的这么复杂,代码其实上来就可以撸出来。
但我还是强调一下,简单题是用来掌握方法论的,动规五部曲将在接下来的动态规划讲解中发挥重要作用,敬请期待!
diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md
index bca7e074..0dcbbb76 100644
--- a/problems/0513.找树左下角的值.md
+++ b/problems/0513.找树左下角的值.md
@@ -9,7 +9,7 @@
# 513.找树左下角的值
-题目地址:[https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v)
+[力扣题目链接]([https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v))
给定一个二叉树,在树的最后一行找到最左边的值。
@@ -39,7 +39,7 @@
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
-如果对二叉树深度和高度还有点疑惑的话,请看:[110.平衡二叉树](https://mp.weixin.qq.com/s/7QeWnxaAB66LjFJOs40XKg)。
+如果对二叉树深度和高度还有点疑惑的话,请看:[110.平衡二叉树](https://programmercarl.com/0110.平衡二叉树.html)。
所以要找深度最大的叶子节点。
@@ -170,7 +170,7 @@ public:
};
```
-如果对回溯部分精简的代码 不理解的话,可以看这篇[257. 二叉树的所有路径](https://mp.weixin.qq.com/s/-x0IL-5eb9W0kZC1-TM0Lw)
+如果对回溯部分精简的代码 不理解的话,可以看这篇[257. 二叉树的所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)
## 迭代法
@@ -179,7 +179,7 @@ public:
只需要记录最后一行第一个节点的数值就可以了。
-如果对层序遍历不了解,看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA),这篇里也给出了层序遍历的模板,稍作修改就一过刷了这道题了。
+如果对层序遍历不了解,看这篇[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),这篇里也给出了层序遍历的模板,稍作修改就一过刷了这道题了。
代码如下:
@@ -209,9 +209,9 @@ public:
本题涉及如下几点:
-* 递归求深度的写法,我们在[110.平衡二叉树](https://mp.weixin.qq.com/s/7QeWnxaAB66LjFJOs40XKg)中详细的分析了深度应该怎么求,高度应该怎么求。
-* 递归中其实隐藏了回溯,在[257. 二叉树的所有路径](https://mp.weixin.qq.com/s/-x0IL-5eb9W0kZC1-TM0Lw)中讲解了究竟哪里使用了回溯,哪里隐藏了回溯。
-* 层次遍历,在[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)深度讲解了二叉树层次遍历。
+* 递归求深度的写法,我们在[110.平衡二叉树](https://programmercarl.com/0110.平衡二叉树.html)中详细的分析了深度应该怎么求,高度应该怎么求。
+* 递归中其实隐藏了回溯,在[257. 二叉树的所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)中讲解了究竟哪里使用了回溯,哪里隐藏了回溯。
+* 层次遍历,在[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)深度讲解了二叉树层次遍历。
所以本题涉及到的点,我们之前都讲解过,这些知识点需要同学们灵活运用,这样就举一反三了。
diff --git a/problems/0516.最长回文子序列.md b/problems/0516.最长回文子序列.md
index 54cea10e..89b5667f 100644
--- a/problems/0516.最长回文子序列.md
+++ b/problems/0516.最长回文子序列.md
@@ -7,7 +7,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
## 516.最长回文子序列
-题目链接:https://leetcode-cn.com/problems/longest-palindromic-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/longest-palindromic-subsequence/)
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。
@@ -29,7 +29,7 @@
## 思路
-我们刚刚做过了 [动态规划:回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw),求的是回文子串,而本题要求的是回文子序列, 要搞清楚这两者之间的区别。
+我们刚刚做过了 [动态规划:回文子串](https://programmercarl.com/0647.回文子串.html),求的是回文子串,而本题要求的是回文子序列, 要搞清楚这两者之间的区别。
**回文子串是要连续的,回文子序列可不是连续的!** 回文子串,回文子序列都是动态规划经典题目。
diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md
index ea2b1777..fda3621b 100644
--- a/problems/0518.零钱兑换II.md
+++ b/problems/0518.零钱兑换II.md
@@ -9,7 +9,7 @@
## 518. 零钱兑换 II
-链接:https://leetcode-cn.com/problems/coin-change-2/
+[力扣题目链接](https://leetcode-cn.com/problems/coin-change-2/)
难度:中等
@@ -46,7 +46,7 @@
这是一道典型的背包问题,一看到钱币数量不限,就知道这是一个完全背包。
-对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)
+对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)
但本题和纯完全背包不一样,**纯完全背包是能否凑成总金额,而本题是要求凑成总金额的个数!**
@@ -78,7 +78,7 @@ dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
所以递推公式:dp[j] += dp[j - coins[i]];
-**这个递推公式大家应该不陌生了,我在讲解01背包题目的时候在这篇[动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw)中就讲解了,求装满背包有几种方法,一般公式都是:dp[j] += dp[j - nums[i]];**
+**这个递推公式大家应该不陌生了,我在讲解01背包题目的时候在这篇[动态规划:目标和!](https://programmercarl.com/0494.目标和.html)中就讲解了,求装满背包有几种方法,一般公式都是:dp[j] += dp[j - nums[i]];**
3. dp数组如何初始化
@@ -93,7 +93,7 @@ dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),还是外层for遍历背包(金钱总额),内层for循环遍历物品(钱币)呢?
-我在[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)中讲解了完全背包的两个for循环的先后顺序都是可以的。
+我在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中讲解了完全背包的两个for循环的先后顺序都是可以的。
**但本题就不行了!**
@@ -170,7 +170,7 @@ public:
## 总结
-本题的递推公式,其实我们在[动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw)中就已经讲过了,**而难点在于遍历顺序!**
+本题的递推公式,其实我们在[动态规划:目标和!](https://programmercarl.com/0494.目标和.html)中就已经讲过了,**而难点在于遍历顺序!**
在求装满背包有几种方案的时候,认清遍历顺序是非常关键的。
diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md
index 04c03b3f..46f6b796 100644
--- a/problems/0530.二叉搜索树的最小绝对差.md
+++ b/problems/0530.二叉搜索树的最小绝对差.md
@@ -9,9 +9,9 @@
> 利用二叉搜索树的特性搞起!
-## 530.二叉搜索树的最小绝对差
+# 530.二叉搜索树的最小绝对差
-题目地址:https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/
+[力扣题目链接](https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/)
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
@@ -21,7 +21,7 @@
提示:树中至少有 2 个节点。
-## 思路
+# 思路
题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。
@@ -101,7 +101,7 @@ public:
## 迭代
-看过这两篇[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg),[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)文章之后,不难写出两种中序遍历的迭代法。
+看过这两篇[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html),[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://programmercarl.com/二叉树的统一迭代法.html)文章之后,不难写出两种中序遍历的迭代法。
下面我给出其中的一种中序遍历的迭代法,代码如下:
@@ -132,7 +132,7 @@ public:
};
```
-## 总结
+# 总结
**遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点。**
@@ -142,15 +142,11 @@ public:
+# 其他语言版本
+## Java
-
-
-## 其他语言版本
-
-
-Java:
递归
```java
class Solution {
@@ -175,38 +171,11 @@ class Solution {
}
}
```
-```Java
-class Solution {
- TreeNode pre;// 记录上一个遍历的结点
- int result = Integer.MAX_VALUE;
- public int getMinimumDifference(TreeNode root) {
- if (root == null) {
- return result;
- }
- // 左
- int left = getMinimumDifference(root.left);
-
- // 中
- if (pre != null) {
- result = Math.min(left, root.val - pre.val);
- }
- pre = root;
- // 右
- int right = getMinimumDifference(root.right);
- result = Math.min(right, result);
- return result;
- }
-}
-```
-Python:
+## Python
+
+递归
```python
-# Definition for a binary tree node.
-# class TreeNode:
-# def __init__(self, val=0, left=None, right=None):
-# self.val = val
-# self.left = left
-# self.right = right
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
res = []
@@ -222,8 +191,10 @@ class Solution:
for i in range(len(res)-1): // 统计有序数组的最小差值
r = min(abs(res[i]-res[i+1]),r)
return r
-
-# 迭代法-中序遍历
+```
+
+迭代法-中序遍历
+```python
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
stack = []
@@ -242,19 +213,13 @@ class Solution:
cur = cur.right
return result
-```
-Go:
-> 中序遍历,然后计算最小差值
+```
+
+## Go:
+
+中序遍历,然后计算最小差值
```go
-/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
- * }
- */
func getMinimumDifference(root *TreeNode) int {
var res []int
findMIn(root,&res)
@@ -299,7 +264,7 @@ func getMinimumDifference(root *TreeNode) int {
}
```
-JavaScript版本
+## JavaScript
```javascript
/**
diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md
index d22cb4bc..df22511d 100644
--- a/problems/0538.把二叉搜索树转换为累加树.md
+++ b/problems/0538.把二叉搜索树转换为累加树.md
@@ -9,7 +9,7 @@
## 538.把二叉搜索树转换为累加树
-题目链接:https://leetcode-cn.com/problems/convert-bst-to-greater-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/convert-bst-to-greater-tree/)
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
@@ -69,7 +69,7 @@
本题依然需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。
-pre指针的使用技巧,我们在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)和[二叉树:我的众数是多少?](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg)都提到了,这是常用的操作手段。
+pre指针的使用技巧,我们在[二叉树:搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)和[二叉树:我的众数是多少?](https://programmercarl.com/0501.二叉搜索树中的众数.html)都提到了,这是常用的操作手段。
* 递归函数参数以及返回值
@@ -129,7 +129,7 @@ public:
## 迭代法
-迭代法其实就是中序模板题了,在[二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)和[二叉树:前中后序统一方式迭代法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)可以选一种自己习惯的写法。
+迭代法其实就是中序模板题了,在[二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:前中后序统一方式迭代法](https://programmercarl.com/二叉树的统一迭代法.html)可以选一种自己习惯的写法。
这里我给出其中的一种,代码如下:
diff --git a/problems/0541.反转字符串II.md b/problems/0541.反转字符串II.md
index 02713c65..469b5685 100644
--- a/problems/0541.反转字符串II.md
+++ b/problems/0541.反转字符串II.md
@@ -12,7 +12,7 @@
# 541. 反转字符串II
-https://leetcode-cn.com/problems/reverse-string-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/reverse-string-ii/)
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
@@ -65,7 +65,7 @@ public:
};
```
-那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。
+那么我们也可以实现自己的reverse函数,其实和题目[344. 反转字符串](https://programmercarl.com/0344.反转字符串.html)道理是一样的。
下面我实现的reverse函数区间是左闭右闭区间,代码如下:
@@ -155,27 +155,34 @@ class Solution {
Python:
```python
-class Solution:
- def reverseStr(self, s: str, k: int) -> str:
+
+class Solution(object):
+ def reverseStr(self, s, k):
"""
- 1. 使用range(start, end, step)来确定需要调换的初始位置
- 2. 对于字符串s = 'abc',如果使用s[0:999] ===> 'abc'。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理。
- 3. 用切片整体替换,而不是一个个替换.
+ :type s: str
+ :type k: int
+ :rtype: str
"""
- def reverse_substring(text):
- left, right = 0, len(text) - 1
+ from functools import reduce
+ # turn s into a list
+ s = list(s)
+
+ # another way to simply use a[::-1], but i feel this is easier to understand
+ def reverse(s):
+ left, right = 0, len(s) - 1
while left < right:
- text[left], text[right] = text[right], text[left]
+ s[left], s[right] = s[right], s[left]
left += 1
right -= 1
- return text
+ return s
- res = list(s)
-
- for cur in range(0, len(s), 2 * k):
- res[cur: cur + k] = reverse_substring(res[cur: cur + k])
+ # make sure we reverse each 2k elements
+ for i in range(0, len(s), 2*k):
+ s[i:(i+k)] = reverse(s[i:(i+k)])
+
+ # combine list into str.
+ return reduce(lambda a, b: a+b, s)
- return ''.join(res)
```
diff --git a/problems/0583.两个字符串的删除操作.md b/problems/0583.两个字符串的删除操作.md
index f6c13039..89a8f57c 100644
--- a/problems/0583.两个字符串的删除操作.md
+++ b/problems/0583.两个字符串的删除操作.md
@@ -8,7 +8,7 @@
## 583. 两个字符串的删除操作
-题目链接:https://leetcode-cn.com/problems/delete-operation-for-two-strings/
+[力扣题目链接](https://leetcode-cn.com/problems/delete-operation-for-two-strings/)
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
@@ -20,7 +20,7 @@
## 思路
-本题和[动态规划:115.不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A)相比,其实就是两个字符串可以都可以删除了,情况虽说复杂一些,但整体思路是不变的。
+本题和[动态规划:115.不同的子序列](https://programmercarl.com/0115.不同的子序列.html)相比,其实就是两个字符串可以都可以删除了,情况虽说复杂一些,但整体思路是不变的。
这次是两个字符串可以相互删了,这种题目也知道用动态规划的思路来解,动规五部曲,分析如下:
diff --git a/problems/0617.合并二叉树.md b/problems/0617.合并二叉树.md
index b24a934b..22a527f9 100644
--- a/problems/0617.合并二叉树.md
+++ b/problems/0617.合并二叉树.md
@@ -7,9 +7,9 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 617.合并二叉树
+# 617.合并二叉树
-题目地址:https://leetcode-cn.com/problems/merge-two-binary-trees/
+[力扣题目链接](https://leetcode-cn.com/problems/merge-two-binary-trees/)
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
@@ -21,7 +21,7 @@
注意: 合并必须从两个树的根节点开始。
-## 思路
+# 思路
相信这道题目很多同学疑惑的点是如何同时遍历两个二叉树呢?
@@ -165,7 +165,7 @@ public:
使用迭代法,如何同时处理两棵树呢?
-思路我们在[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中的迭代法已经讲过一次了,求二叉树对称的时候就是把两个树的节点同时加入队列进行比较。
+思路我们在[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)中的迭代法已经讲过一次了,求二叉树对称的时候就是把两个树的节点同时加入队列进行比较。
本题我们也使用队列,模拟的层序遍历,代码如下:
@@ -209,7 +209,7 @@ public:
};
```
-## 拓展
+# 拓展
当然也可以秀一波指针的操作,这是我写的野路子,大家就随便看看就行了,以防带跑遍了。
@@ -241,21 +241,21 @@ public:
};
```
-## 总结
+# 总结
合并二叉树,也是二叉树操作的经典题目,如果没有接触过的话,其实并不简单,因为我们习惯了操作一个二叉树,一起操作两个二叉树,还会有点懵懵的。
-这不是我们第一次操作两颗二叉树了,在[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中也一起操作了两棵二叉树。
+这不是我们第一次操作两颗二叉树了,在[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)中也一起操作了两棵二叉树。
迭代法中,一般一起操作两个树都是使用队列模拟类似层序遍历,同时处理两个树的节点,这种方式最好理解,如果用模拟递归的思路的话,要复杂一些。
最后拓展中,我给了一个操作指针的野路子,大家随便看看就行了,如果学习C++的话,可以在去研究研究。
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -311,7 +311,7 @@ class Solution {
}
```
-Python:
+## Python
**递归法 - 前序遍历**
```python
@@ -374,7 +374,7 @@ class Solution:
return root1
```
-Go:
+## Go
```go
/**
@@ -468,7 +468,7 @@ func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
}
```
-JavaScript:
+## JavaScript
```javascript
/**
diff --git a/problems/0647.回文子串.md b/problems/0647.回文子串.md
index f81801b7..7b90ca0c 100644
--- a/problems/0647.回文子串.md
+++ b/problems/0647.回文子串.md
@@ -8,7 +8,7 @@
## 647. 回文子串
-题目链接:https://leetcode-cn.com/problems/palindromic-substrings/
+[力扣题目链接](https://leetcode-cn.com/problems/palindromic-substrings/)
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
diff --git a/problems/0649.Dota2参议院.md b/problems/0649.Dota2参议院.md
index b73686c4..9cec7401 100644
--- a/problems/0649.Dota2参议院.md
+++ b/problems/0649.Dota2参议院.md
@@ -67,7 +67,7 @@ Dota2 参议院由来自两派的参议员组成。现在参议院希望对一
局部最优可以退出全局最优,举不出反例,那么试试贪心。
-如果对贪心算法理论基础还不了解的话,可以看看这篇:[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg) ,相信看完之后对贪心就有基本的了解了。
+如果对贪心算法理论基础还不了解的话,可以看看这篇:[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html) ,相信看完之后对贪心就有基本的了解了。
# 代码实现
diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md
index 8c310a21..1a6d39af 100644
--- a/problems/0654.最大二叉树.md
+++ b/problems/0654.最大二叉树.md
@@ -7,9 +7,9 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 654.最大二叉树
+# 654.最大二叉树
-题目地址:https://leetcode-cn.com/problems/maximum-binary-tree/
+[力扣题目地址](https://leetcode-cn.com/problems/maximum-binary-tree/)
给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
@@ -27,7 +27,7 @@
给定的数组的大小在 [1, 1000] 之间。
-## 思路
+# 思路
最大二叉树的构建过程如下:
@@ -41,7 +41,7 @@
代码如下:
-```
+```CPP
TreeNode* constructMaximumBinaryTree(vector& nums)
```
@@ -53,7 +53,7 @@ TreeNode* constructMaximumBinaryTree(vector& nums)
代码如下:
-```
+```CPP
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
@@ -68,7 +68,7 @@ if (nums.size() == 1) {
1. 先要找到数组中最大的值和对应的下表, 最大的值构造根节点,下表用来下一步分割数组。
代码如下:
-```
+```CPP
int maxValue = 0;
int maxValueIndex = 0;
for (int i = 0; i < nums.size(); i++) {
@@ -86,7 +86,7 @@ node->val = maxValue;
这里要判断maxValueIndex > 0,因为要保证左区间至少有一个数值。
代码如下:
-```
+```CPP
if (maxValueIndex > 0) {
vector newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
@@ -99,7 +99,7 @@ if (maxValueIndex > 0) {
代码如下:
-```
+```CPP
if (maxValueIndex < (nums.size() - 1)) {
vector newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
@@ -143,7 +143,7 @@ public:
以上代码比较冗余,效率也不高,每次还要切割的时候每次都要定义新的vector(也就是数组),但逻辑比较清晰。
-和文章[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中一样的优化思路,就是每次分隔不用定义新的数组,而是通过下表索引直接在原数组上操作。
+和文章[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)中一样的优化思路,就是每次分隔不用定义新的数组,而是通过下表索引直接在原数组上操作。
优化后代码如下:
@@ -177,7 +177,7 @@ public:
};
```
-## 拓展
+# 拓展
可以发现上面的代码看上去简洁一些,**主要是因为第二版其实是允许空节点进入递归,所以不用在递归的时候加判断节点是否为空**
@@ -209,10 +209,10 @@ root->right = traversal(nums, maxValueIndex + 1, right);
第二版相应的终止条件,是遇到空节点,也就是数组区间为0,就终止了。
+# 总结
-## 总结
-这道题目其实和 [二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 是一个思路,比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 还简单一些。
+这道题目其实和 [二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 是一个思路,比[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 还简单一些。
**注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下表索引直接在原数组上操作,这样可以节约时间和空间上的开销。**
@@ -220,10 +220,10 @@ root->right = traversal(nums, maxValueIndex + 1, right);
其实就是不同代码风格的实现,**一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。**
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -255,14 +255,9 @@ class Solution {
}
```
-Python:
+## Python
+
```python
-# Definition for a binary tree node.
-# class TreeNode:
-# def __init__(self, val=0, left=None, right=None):
-# self.val = val
-# self.left = left
-# self.right = right
//递归法
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
@@ -276,9 +271,8 @@ class Solution:
return root
```
-Go:
+## Go
-> 654. 最大二叉树
```go
/**
@@ -311,7 +305,7 @@ func findMax(nums []int) (index int){
}
```
-JavaScript版本
+## JavaScript
```javascript
/**
diff --git a/problems/0657.机器人能否返回原点.md b/problems/0657.机器人能否返回原点.md
index 480e830f..ffa5d6f2 100644
--- a/problems/0657.机器人能否返回原点.md
+++ b/problems/0657.机器人能否返回原点.md
@@ -9,7 +9,7 @@
# 657. 机器人能否返回原点
-题目地址:https://leetcode-cn.com/problems/robot-return-to-origin/
+[力扣题目链接](https://leetcode-cn.com/problems/robot-return-to-origin/)
在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。
diff --git a/problems/0669.修剪二叉搜索树.md b/problems/0669.修剪二叉搜索树.md
index 267497b4..fe18e5a5 100644
--- a/problems/0669.修剪二叉搜索树.md
+++ b/problems/0669.修剪二叉搜索树.md
@@ -12,7 +12,7 @@
## 669. 修剪二叉搜索树
-题目链接:https://leetcode-cn.com/problems/trim-a-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/trim-a-binary-search-tree/)
给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
@@ -71,7 +71,7 @@ public:
但是有返回值,更方便,可以通过递归函数的返回值来移除节点。
-这样的做法在[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)和[二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw)中大家已经了解过了。
+这样的做法在[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)和[二叉树:搜索树中的删除操作](https://programmercarl.com/0450.删除二叉搜索树中的节点.html)中大家已经了解过了。
代码如下:
diff --git a/problems/0674.最长连续递增序列.md b/problems/0674.最长连续递增序列.md
index 0fe1c49a..3f3b5e6f 100644
--- a/problems/0674.最长连续递增序列.md
+++ b/problems/0674.最长连续递增序列.md
@@ -8,7 +8,7 @@
## 674. 最长连续递增序列
-题目链接:https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/)
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
@@ -24,7 +24,7 @@
输入:nums = [2,2,2,2,2]
输出:1
解释:最长连续递增序列是 [2], 长度为1。
-
+
提示:
* 0 <= nums.length <= 10^4
@@ -33,7 +33,7 @@
## 思路
-本题相对于昨天的[动态规划:300.最长递增子序列](https://mp.weixin.qq.com/s/f8nLO3JGfgriXep_gJQpqQ)最大的区别在于“连续”。
+本题相对于昨天的[动态规划:300.最长递增子序列](https://programmercarl.com/0300.最长上升子序列.html)最大的区别在于“连续”。
本题要求的是最长**连续**递增序列
@@ -53,7 +53,7 @@
即:dp[i + 1] = dp[i] + 1;
-**注意这里就体现出和[动态规划:300.最长递增子序列](https://mp.weixin.qq.com/s/f8nLO3JGfgriXep_gJQpqQ)的区别!**
+**注意这里就体现出和[动态规划:300.最长递增子序列](https://programmercarl.com/0300.最长上升子序列.html)的区别!**
因为本题要求连续递增子序列,所以就必要比较nums[i + 1]与nums[i],而不用去比较nums[j]与nums[i] (j是在0到i之间遍历)。
@@ -144,7 +144,7 @@ public:
本题也是动规里子序列问题的经典题目,但也可以用贪心来做,大家也会发现贪心好像更简单一点,而且空间复杂度仅是O(1)。
-在动规分析中,关键是要理解和[动态规划:300.最长递增子序列](https://mp.weixin.qq.com/s/f8nLO3JGfgriXep_gJQpqQ)的区别。
+在动规分析中,关键是要理解和[动态规划:300.最长递增子序列](https://programmercarl.com/0300.最长上升子序列.html)的区别。
**要联动起来,才能理解递增子序列怎么求,递增连续子序列又要怎么求**。
diff --git a/problems/0685.冗余连接II.md b/problems/0685.冗余连接II.md
index e282e620..68d0376e 100644
--- a/problems/0685.冗余连接II.md
+++ b/problems/0685.冗余连接II.md
@@ -11,7 +11,7 @@
# 685.冗余连接II
-题目地址:https://leetcode-cn.com/problems/redundant-connection-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/redundant-connection-ii/)
在本问题中,有根树指满足以下条件的 有向 图。该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。
diff --git a/problems/0700.二叉搜索树中的搜索.md b/problems/0700.二叉搜索树中的搜索.md
index 68d30e3f..c25ea12f 100644
--- a/problems/0700.二叉搜索树中的搜索.md
+++ b/problems/0700.二叉搜索树中的搜索.md
@@ -7,9 +7,9 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 700.二叉搜索树中的搜索
+# 700.二叉搜索树中的搜索
-题目地址:https://leetcode-cn.com/problems/search-in-a-binary-search-tree/
+[力扣题目地址](https://leetcode-cn.com/problems/search-in-a-binary-search-tree/)
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
@@ -19,11 +19,11 @@
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
-## 思路
+# 思路
之前我们讲了都是普通二叉树,那么接下来看看二叉搜索树。
-在[关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A)中,我们已经讲过了二叉搜索树。
+在[关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html)中,我们已经讲过了二叉搜索树。
二叉搜索树是一个有序树:
@@ -73,7 +73,7 @@ return NULL;
这里可能会疑惑,在递归遍历的时候,什么时候直接return 递归函数的返回值,什么时候不用加这个 return呢。
-我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。
+我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中讲了,如果要搜索一条边,递归函数就要加返回值,这里也是一样的道理。
**因为搜索到目标节点了,就要立即return了,这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。**
@@ -125,7 +125,7 @@ public:
第一次看到了如此简单的迭代法,是不是感动的痛哭流涕,哭一会~
-## 总结
+# 总结
本篇我们介绍了二叉搜索树的遍历方式,因为二叉搜索树的有序性,遍历的时候要比普通二叉树简单很多。
@@ -138,9 +138,9 @@ public:
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -207,17 +207,11 @@ class Solution {
}
```
-Python:
+## Python
递归法:
```python
-# Definition for a binary tree node.
-# class TreeNode:
-# def __init__(self, val=0, left=None, right=None):
-# self.val = val
-# self.left = left
-# self.right = right
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
# 为什么要有返回值:
@@ -248,19 +242,11 @@ class Solution:
```
-Go:
+## Go
-> 递归法
+递归法:
```go
-/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
- * }
- */
//递归法
func searchBST(root *TreeNode, val int) *TreeNode {
if root==nil||root.Val==val{
@@ -273,17 +259,9 @@ func searchBST(root *TreeNode, val int) *TreeNode {
}
```
-> 迭代法
+迭代法:
```go
-/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
- * }
- */
//迭代法
func searchBST(root *TreeNode, val int) *TreeNode {
for root!=nil{
@@ -299,9 +277,9 @@ func searchBST(root *TreeNode, val int) *TreeNode {
}
```
-JavaScript版本
+## JavaScript
-> 递归
+递归:
```javascript
/**
@@ -327,9 +305,9 @@ var searchBST = function (root, val) {
return searchBST(root.right, val);
return null;
};
-```
+```
-> 迭代
+迭代:
```javascript
/**
diff --git a/problems/0701.二叉搜索树中的插入操作.md b/problems/0701.二叉搜索树中的插入操作.md
index fdaba43e..c245ddcf 100644
--- a/problems/0701.二叉搜索树中的插入操作.md
+++ b/problems/0701.二叉搜索树中的插入操作.md
@@ -9,7 +9,7 @@
## 701.二叉搜索树中的插入操作
-链接:https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/insert-into-a-binary-search-tree/)
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。
@@ -164,11 +164,11 @@ public:
## 迭代
-再来看看迭代法,对二叉搜索树迭代写法不熟悉,可以看这篇:[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)
+再来看看迭代法,对二叉搜索树迭代写法不熟悉,可以看这篇:[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)
在迭代法遍历的过程中,需要记录一下当前遍历的节点的父节点,这样才能做插入节点的操作。
-在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)和[二叉树:我的众数是多少?](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg)中,都是用了记录pre和cur两个指针的技巧,本题也是一样的。
+在[二叉树:搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)和[二叉树:我的众数是多少?](https://programmercarl.com/0501.二叉搜索树中的众数.html)中,都是用了记录pre和cur两个指针的技巧,本题也是一样的。
代码如下:
diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md
index 2efbd7c4..e576443e 100644
--- a/problems/0704.二分查找.md
+++ b/problems/0704.二分查找.md
@@ -9,7 +9,7 @@
## 704. 二分查找
-题目链接:https://leetcode-cn.com/problems/binary-search/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-search/)
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
@@ -139,7 +139,7 @@ public:
## 相关题目推荐
-* [35.搜索插入位置](./0035.搜索插入位置.md)
+* [35.搜索插入位置](https://programmercarl.com/0035.搜索插入位置.html)
* 34.在排序数组中查找元素的第一个和最后一个位置
* 69.x 的平方根
* 367.有效的完全平方数
diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md
index 10a3e948..e05165a9 100644
--- a/problems/0707.设计链表.md
+++ b/problems/0707.设计链表.md
@@ -11,7 +11,7 @@
# 707.设计链表
-https://leetcode-cn.com/problems/design-linked-list/
+[力扣题目链接](https://leetcode-cn.com/problems/design-linked-list/)
题意:
@@ -28,9 +28,9 @@ https://leetcode-cn.com/problems/design-linked-list/
# 思路
-如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)
+如果对链表的基础知识还不太懂,可以看这篇文章:[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html)
-如果对链表的虚拟头结点不清楚,可以看这篇文章:[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)
+如果对链表的虚拟头结点不清楚,可以看这篇文章:[链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
删除链表节点:

diff --git a/problems/0714.买卖股票的最佳时机含手续费.md b/problems/0714.买卖股票的最佳时机含手续费.md
index b0a64bd2..4ac4684e 100644
--- a/problems/0714.买卖股票的最佳时机含手续费.md
+++ b/problems/0714.买卖股票的最佳时机含手续费.md
@@ -9,7 +9,7 @@
## 714. 买卖股票的最佳时机含手续费
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/)
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
@@ -37,11 +37,11 @@
## 思路
-本题相对于[贪心算法:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg),多添加了一个条件就是手续费。
+本题相对于[贪心算法:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),多添加了一个条件就是手续费。
## 贪心算法
-在[贪心算法:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg)中使用贪心策略不用关心具体什么时候买卖,只要收集每天的正利润,最后稳稳的就是最大利润了。
+在[贪心算法:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html)中使用贪心策略不用关心具体什么时候买卖,只要收集每天的正利润,最后稳稳的就是最大利润了。
而本题有了手续费,就要关系什么时候买卖了,因为计算所获得利润,需要考虑买卖利润可能不足以手续费的情况。
@@ -97,7 +97,7 @@ public:
我在公众号「代码随想录」里将在下一个系列详细讲解动态规划,所以本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
-相对于[贪心算法:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg)的动态规划解法中,只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
+相对于[贪心算法:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html)的动态规划解法中,只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
C++代码如下:
diff --git a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md
index 53952a7f..50db8868 100644
--- a/problems/0714.买卖股票的最佳时机含手续费(动态规划).md
+++ b/problems/0714.买卖股票的最佳时机含手续费(动态规划).md
@@ -8,7 +8,7 @@
## 714.买卖股票的最佳时机含手续费
-题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
+[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/)
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
@@ -36,7 +36,7 @@
## 思路
-在讲解贪心专题的时候,我们已经讲过本题了[贪心算法:买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/olWrUuDEYw2Jx5rMeG7XAg)
+在讲解贪心专题的时候,我们已经讲过本题了[贪心算法:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费.html)
使用贪心算法,的性能是:
* 时间复杂度:O(n)
@@ -44,7 +44,7 @@
那么我们再来看看是使用动规的方法如何解题。
-相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
+相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
唯一差别在于递推公式部分,所以本篇也就不按照动规五部曲详细讲解了,主要讲解一下递推公式部分。
@@ -68,7 +68,7 @@ dp[i][1] 表示第i天不持有股票所得最多现金
所以:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
-**本题和[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)的区别就是这里需要多一个减去手续费的操作**。
+**本题和[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html)的区别就是这里需要多一个减去手续费的操作**。
以上分析完毕,C++代码如下:
diff --git a/problems/0718.最长重复子数组.md b/problems/0718.最长重复子数组.md
index 2fe38f0a..9e3da663 100644
--- a/problems/0718.最长重复子数组.md
+++ b/problems/0718.最长重复子数组.md
@@ -8,7 +8,7 @@
## 718. 最长重复子数组
-题目链接:https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/
+[力扣题目链接](https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/)
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
diff --git a/problems/0738.单调递增的数字.md b/problems/0738.单调递增的数字.md
index 82f7f3ae..f63a05b8 100644
--- a/problems/0738.单调递增的数字.md
+++ b/problems/0738.单调递增的数字.md
@@ -8,7 +8,7 @@
## 738.单调递增的数字
-题目链接: https://leetcode-cn.com/problems/monotone-increasing-digits/
+[力扣题目链接](https://leetcode-cn.com/problems/monotone-increasing-digits/)
给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。
diff --git a/problems/0739.每日温度.md b/problems/0739.每日温度.md
index ddcbe428..b00701ed 100644
--- a/problems/0739.每日温度.md
+++ b/problems/0739.每日温度.md
@@ -9,8 +9,7 @@
# 739. 每日温度
-
-https://leetcode-cn.com/problems/daily-temperatures/
+[力扣题目链接](https://leetcode-cn.com/problems/daily-temperatures/)
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
diff --git a/problems/0746.使用最小花费爬楼梯.md b/problems/0746.使用最小花费爬楼梯.md
index 9b691c5f..eb2a437a 100644
--- a/problems/0746.使用最小花费爬楼梯.md
+++ b/problems/0746.使用最小花费爬楼梯.md
@@ -8,7 +8,7 @@
## 746. 使用最小花费爬楼梯
-题目链接:https://leetcode-cn.com/problems/min-cost-climbing-stairs/
+[力扣题目链接](https://leetcode-cn.com/problems/min-cost-climbing-stairs/)
数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。
@@ -34,7 +34,7 @@
## 思路
-这道题目可以说是昨天[动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw)的花费版本。
+这道题目可以说是昨天[动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html)的花费版本。
**注意题目描述:每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯**
@@ -185,9 +185,9 @@ public:
# 总结
-大家可以发现这道题目相对于 昨天的[动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw)有难了一点,但整体思路是一样。
+大家可以发现这道题目相对于 昨天的[动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html)有难了一点,但整体思路是一样。
-从[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)到 [动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw)再到今天这道题目,录友们感受到循序渐进的梯度了嘛。
+从[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)到 [动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html)再到今天这道题目,录友们感受到循序渐进的梯度了嘛。
每个系列开始的时候,都有录友和我反馈说题目太简单了,赶紧上难度,但也有录友和我说有点难了,快跟不上了。
diff --git a/problems/0763.划分字母区间.md b/problems/0763.划分字母区间.md
index ccf654d4..43c663c2 100644
--- a/problems/0763.划分字母区间.md
+++ b/problems/0763.划分字母区间.md
@@ -9,7 +9,7 @@
## 763.划分字母区间
-题目链接: https://leetcode-cn.com/problems/partition-labels/
+[力扣题目链接](https://leetcode-cn.com/problems/partition-labels/)
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
@@ -20,7 +20,7 @@
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
-
+
提示:
* S的长度在[1, 500]之间。
diff --git a/problems/0841.钥匙和房间.md b/problems/0841.钥匙和房间.md
index bd7c99c9..4a0185ec 100644
--- a/problems/0841.钥匙和房间.md
+++ b/problems/0841.钥匙和房间.md
@@ -10,7 +10,7 @@
# 841.钥匙和房间
-题目地址:https://leetcode-cn.com/problems/keys-and-rooms/
+[力扣题目链接](https://leetcode-cn.com/problems/keys-and-rooms/)
有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。
diff --git a/problems/0844.比较含退格的字符串.md b/problems/0844.比较含退格的字符串.md
index 32232c4a..e6bf3493 100644
--- a/problems/0844.比较含退格的字符串.md
+++ b/problems/0844.比较含退格的字符串.md
@@ -9,7 +9,7 @@
# 844.比较含退格的字符串
-题目链接:https://leetcode-cn.com/problems/backspace-string-compare/
+[力扣题目链接](https://leetcode-cn.com/problems/backspace-string-compare/)
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
@@ -42,7 +42,7 @@
## 普通方法(使用栈的思路)
-这道题目一看就是要使用栈的节奏,这种匹配(消除)问题也是栈的擅长所在,跟着一起刷题的同学应该知道,在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg),我就已经提过了一次使用栈来做类似的事情了。
+这道题目一看就是要使用栈的节奏,这种匹配(消除)问题也是栈的擅长所在,跟着一起刷题的同学应该知道,在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html),我就已经提过了一次使用栈来做类似的事情了。
**那么本题,确实可以使用栈的思路,但是没有必要使用栈,因为最后比较的时候还要比较栈里的元素,有点麻烦**。
diff --git a/problems/0860.柠檬水找零.md b/problems/0860.柠檬水找零.md
index 792bee9a..46e05419 100644
--- a/problems/0860.柠檬水找零.md
+++ b/problems/0860.柠檬水找零.md
@@ -9,7 +9,7 @@
## 860.柠檬水找零
-题目链接:https://leetcode-cn.com/problems/lemonade-change/
+[力扣题目链接](https://leetcode-cn.com/problems/lemonade-change/)
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。
diff --git a/problems/0925.长按键入.md b/problems/0925.长按键入.md
index c851a8df..3502f2fb 100644
--- a/problems/0925.长按键入.md
+++ b/problems/0925.长按键入.md
@@ -8,7 +8,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
# 925.长按键入
-题目链接:https://leetcode-cn.com/problems/long-pressed-name/
+[力扣题目链接](https://leetcode-cn.com/problems/long-pressed-name/)
你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。
diff --git a/problems/0941.有效的山脉数组.md b/problems/0941.有效的山脉数组.md
index 98344949..ef5739e3 100644
--- a/problems/0941.有效的山脉数组.md
+++ b/problems/0941.有效的山脉数组.md
@@ -9,7 +9,7 @@
# 941.有效的山脉数组
-题目链接:https://leetcode-cn.com/problems/valid-mountain-array/
+[力扣题目链接](https://leetcode-cn.com/problems/valid-mountain-array/)
给定一个整数数组 arr,如果它是有效的山脉数组就返回 true,否则返回 false。
@@ -71,7 +71,7 @@ public:
};
```
-如果想系统学一学双指针的话, 可以看一下这篇[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA)
+如果想系统学一学双指针的话, 可以看一下这篇[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)
# 其他语言版本
diff --git a/problems/0968.监控二叉树.md b/problems/0968.监控二叉树.md
index 380ca8f8..c715279a 100644
--- a/problems/0968.监控二叉树.md
+++ b/problems/0968.监控二叉树.md
@@ -9,7 +9,7 @@
## 968.监控二叉树
-题目地址 : https://leetcode-cn.com/problems/binary-tree-cameras/
+[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-cameras/)
给定一个二叉树,我们在树的节点上安装摄像头。
diff --git a/problems/0977.有序数组的平方.md b/problems/0977.有序数组的平方.md
index 71c46401..13142853 100644
--- a/problems/0977.有序数组的平方.md
+++ b/problems/0977.有序数组的平方.md
@@ -10,7 +10,7 @@
# 977.有序数组的平方
-https://leetcode-cn.com/problems/squares-of-a-sorted-array/
+[力扣题目链接](https://leetcode-cn.com/problems/squares-of-a-sorted-array/)
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md
index a789373b..39151185 100644
--- a/problems/1002.查找常用字符.md
+++ b/problems/1002.查找常用字符.md
@@ -10,7 +10,7 @@
# 1002. 查找常用字符
-https://leetcode-cn.com/problems/find-common-characters/
+[力扣题目链接](https://leetcode-cn.com/problems/find-common-characters/)
给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
@@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/find-common-characters/
【示例二】
输入:["cool","lock","cook"]
输出:["c","o"]
-
+
# 思路
@@ -40,9 +40,9 @@ https://leetcode-cn.com/problems/find-common-characters/
可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。
-那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。
+那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。
-如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)。
+如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://programmercarl.com/0242.有效的字母异位词.html)。
了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。
@@ -233,41 +233,7 @@ var commonChars = function (words) {
return res
};
```
-GO
-```golang
-func commonChars(words []string) []string {
- length:=len(words)
- fre:=make([][]int,0)//统计每个字符串的词频
- res:=make([]string,0)
- //统计词频
- for i:=0;ib{
- return b
- }
- return a
-}
-```
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
diff --git a/problems/1005.K次取反后最大化的数组和.md b/problems/1005.K次取反后最大化的数组和.md
index a689fbf7..8bdd0f41 100644
--- a/problems/1005.K次取反后最大化的数组和.md
+++ b/problems/1005.K次取反后最大化的数组和.md
@@ -9,7 +9,7 @@
## 1005.K次取反后最大化的数组和
-题目地址:https://leetcode-cn.com/problems/maximize-sum-of-array-after-k-negations/
+[力扣题目链接](https://leetcode-cn.com/problems/maximize-sum-of-array-after-k-negations/)
给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。)
diff --git a/problems/1035.不相交的线.md b/problems/1035.不相交的线.md
index 3172cfc7..b71a5199 100644
--- a/problems/1035.不相交的线.md
+++ b/problems/1035.不相交的线.md
@@ -8,7 +8,7 @@
## 1035.不相交的线
-题目链接: https://leetcode-cn.com/problems/uncrossed-lines/
+[力扣题目链接](https://leetcode-cn.com/problems/uncrossed-lines/)
我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。
@@ -35,13 +35,13 @@
这么分析完之后,大家可以发现:**本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!**
-那么本题就和我们刚刚讲过的这道题目[动态规划:1143.最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg)就是一样一样的了。
+那么本题就和我们刚刚讲过的这道题目[动态规划:1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)就是一样一样的了。
一样到什么程度呢? 把字符串名字改一下,其他代码都不用改,直接copy过来就行了。
-其实本题就是求最长公共子序列的长度,介于我们刚刚讲过[动态规划:1143.最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg),所以本题我就不再做动规五部曲分析了。
+其实本题就是求最长公共子序列的长度,介于我们刚刚讲过[动态规划:1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html),所以本题我就不再做动规五部曲分析了。
-如果大家有点遗忘了最长公共子序列,就再看一下这篇:[动态规划:1143.最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg)
+如果大家有点遗忘了最长公共子序列,就再看一下这篇:[动态规划:1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)
本题代码如下:
@@ -66,9 +66,9 @@ public:
## 总结
-看到代码大家也可以发现其实就是求两个字符串的最长公共子序列,但如果没有做过[1143.最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg),本题其实还有很有难度的。
+看到代码大家也可以发现其实就是求两个字符串的最长公共子序列,但如果没有做过[1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html),本题其实还有很有难度的。
-这是Carl为什么要先讲[1143.最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg)再讲本题,大家会发现一个正确的刷题顺序对算法学习是非常重要的!
+这是Carl为什么要先讲[1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)再讲本题,大家会发现一个正确的刷题顺序对算法学习是非常重要的!
这也是Carl做了很多题目(包括ACM和力扣)才总结出来的规律,大家仔细体会一下哈。
diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md
index b60a8d1d..52d2bc95 100644
--- a/problems/1047.删除字符串中的所有相邻重复项.md
+++ b/problems/1047.删除字符串中的所有相邻重复项.md
@@ -13,7 +13,7 @@
# 1047. 删除字符串中的所有相邻重复项
-https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/
+[力扣题目链接](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/)
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
@@ -26,7 +26,7 @@ https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/
* 输入:"abbaca"
* 输出:"ca"
* 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
-
+
提示:
* 1 <= S.length <= 20000
@@ -197,38 +197,15 @@ class Solution {
Python:
```python3
-# 方法一,使用栈,推荐!
class Solution:
def removeDuplicates(self, s: str) -> str:
- res = list()
- for item in s:
- if res and res[-1] == item:
- res.pop()
+ t = list()
+ for i in s:
+ if t and t[-1] == i:
+ t.pop(-1)
else:
- res.append(item)
- return "".join(res) # 字符串拼接
-```
-
-```python3
-# 方法二,使用双指针模拟栈,如果不让用栈可以作为备选方法。
-class Solution:
- def removeDuplicates(self, s: str) -> str:
- res = list(s)
- slow = fast = 0
- length = len(res)
-
- while fast < length:
- # 如果一样直接换,不一样会把后面的填在slow的位置
- res[slow] = res[fast]
-
- # 如果发现和前一个一样,就退一格指针
- if slow > 0 and res[slow] == res[slow - 1]:
- slow -= 1
- else:
- slow += 1
- fast += 1
-
- return ''.join(res[0: slow])
+ t.append(i)
+ return "".join(t) # 字符串拼接
```
Go:
diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md
index 7b71eae4..25299f14 100644
--- a/problems/1049.最后一块石头的重量II.md
+++ b/problems/1049.最后一块石头的重量II.md
@@ -9,7 +9,7 @@
## 1049. 最后一块石头的重量 II
-题目链接:https://leetcode-cn.com/problems/last-stone-weight-ii/
+[力扣题目链接](https://leetcode-cn.com/problems/last-stone-weight-ii/)
题目难度:中等
@@ -29,7 +29,7 @@
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
-
+
提示:
* 1 <= stones.length <= 30
@@ -39,12 +39,12 @@
如果对背包问题不都熟悉先看这两篇:
-* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)
-* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)
+* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)
+* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)
本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,**这样就化解成01背包问题了**。
-是不是感觉和昨天讲解的[416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)非常像了。
+是不是感觉和昨天讲解的[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)非常像了。
本题物品的重量为store[i],物品的价值也为store[i]。
@@ -89,7 +89,7 @@ vector dp(15001, 0);
4. 确定遍历顺序
-在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
+在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
代码如下:
@@ -143,9 +143,9 @@ public:
## 总结
-本题其实和[416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)几乎是一样的,只是最后对dp[target]的处理方式不同。
+本题其实和[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)几乎是一样的,只是最后对dp[target]的处理方式不同。
-[416. 分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ)相当于是求背包是否正好装满,而本题是求背包最多能装多少。
+[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)相当于是求背包是否正好装满,而本题是求背包最多能装多少。
diff --git a/problems/1143.最长公共子序列.md b/problems/1143.最长公共子序列.md
index c0468d08..b3b5e6c0 100644
--- a/problems/1143.最长公共子序列.md
+++ b/problems/1143.最长公共子序列.md
@@ -8,7 +8,7 @@
## 1143.最长公共子序列
-题目链接: https://leetcode-cn.com/problems/longest-common-subsequence/
+[力扣题目链接](https://leetcode-cn.com/problems/longest-common-subsequence/)
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
@@ -41,7 +41,7 @@
## 思路
-本题和[动态规划:718. 最长重复子数组](https://mp.weixin.qq.com/s/U5WaWqBwdoxzQDotOdWqZg)区别在于这里不要求是连续的了,但要有相对顺序,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
+本题和[动态规划:718. 最长重复子数组](https://programmercarl.com/0718.最长重复子数组.html)区别在于这里不要求是连续的了,但要有相对顺序,即:"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
继续动规五部曲分析如下:
diff --git a/problems/1207.独一无二的出现次数.md b/problems/1207.独一无二的出现次数.md
index 1c09ee8a..027c9f5a 100644
--- a/problems/1207.独一无二的出现次数.md
+++ b/problems/1207.独一无二的出现次数.md
@@ -8,7 +8,7 @@
# 1207.独一无二的出现次数
-链接:https://leetcode-cn.com/problems/unique-number-of-occurrences/
+[力扣题目链接](https://leetcode-cn.com/problems/unique-number-of-occurrences/)
给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。
@@ -35,9 +35,9 @@
# 思路
-这道题目数组在是哈希法中的经典应用,如果对数组在哈希法中的使用还不熟悉的同学可以看这两篇:[数组在哈希法中的应用](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)和[哈希法:383. 赎金信](https://mp.weixin.qq.com/s/qAXqv--UERmiJNNpuphOUQ)
+这道题目数组在是哈希法中的经典应用,如果对数组在哈希法中的使用还不熟悉的同学可以看这两篇:[数组在哈希法中的应用](https://programmercarl.com/0242.有效的字母异位词.html)和[哈希法:383. 赎金信](https://programmercarl.com/0383.赎金信.html)
-进而可以学习一下[set在哈希法中的应用](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q),以及[map在哈希法中的应用](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)
+进而可以学习一下[set在哈希法中的应用](https://programmercarl.com/0349.两个数组的交集.html),以及[map在哈希法中的应用](https://programmercarl.com/0001.两数之和.html)
回归本题,**本题强调了-1000 <= arr[i] <= 1000**,那么就可以用数组来做哈希,arr[i]作为哈希表(数组)的下标,那么arr[i]可以是负数,怎么办?负数不能做数组下标。
diff --git a/problems/1356.根据数字二进制下1的数目排序.md b/problems/1356.根据数字二进制下1的数目排序.md
index 300aa0e2..660434a2 100644
--- a/problems/1356.根据数字二进制下1的数目排序.md
+++ b/problems/1356.根据数字二进制下1的数目排序.md
@@ -7,112 +7,115 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-# 1365.有多少小于当前数字的数字
+
+# 1356. 根据数字二进制下 1 的数目排序
+
+[力扣题目链接](https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits/)
题目链接:https://leetcode-cn.com/problems/sort-integers-by-the-number-of-1-bits/
-给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。
+给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
-换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
-
-以数组形式返回答案。
+如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
+请你返回排序后的数组。
示例 1:
-输入:nums = [8,1,2,2,3]
-输出:[4,0,1,1,3]
-解释:
-对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。
-对于 nums[1]=1 不存在比它小的数字。
-对于 nums[2]=2 存在一个比它小的数字:(1)。
-对于 nums[3]=2 存在一个比它小的数字:(1)。
-对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。
+* 输入:arr = [0,1,2,3,4,5,6,7,8]
+* 输出:[0,1,2,4,8,3,5,6,7]
+* 解释:[0] 是唯一一个有 0 个 1 的数。
+[1,2,4,8] 都有 1 个 1 。
+[3,5,6] 有 2 个 1 。
+[7] 有 3 个 1 。按照 1 的个数排序得到的结果数组为 [0,1,2,4,8,3,5,6,7]
+
示例 2:
-输入:nums = [6,5,4,8]
-输出:[2,1,0,3]
+* 输入:arr = [1024,512,256,128,64,32,16,8,4,2,1]
+* 输出:[1,2,4,8,16,32,64,128,256,512,1024]
+* 解释:数组中所有整数二进制下都只有 1 个 1 ,所以你需要按照数值大小将它们排序。
示例 3:
-输入:nums = [7,7,7,7]
-输出:[0,0,0,0]
+* 输入:arr = [10000,10000]
+* 输出:[10000,10000]
+
+示例 4:
+* 输入:arr = [2,3,5,7,11,13,17,19]
+* 输出:[2,3,5,17,7,11,13,19]
+
+示例 5:
+* 输入:arr = [10,100,1000,10000]
+* 输出:[10,100,10000,1000]
+
-提示:
-* 2 <= nums.length <= 500
-* 0 <= nums[i] <= 100
# 思路
-两层for循环暴力查找,时间复杂度明显为O(n^2)。
+这道题其实是考察如何计算一个数的二进制中1的数量。
-那么我们来看一下如何优化。
+我提供两种方法:
-首先要找小于当前数字的数字,那么从小到大排序之后,该数字之前的数字就都是比它小的了。
+* 方法一:
-所以可以定义一个新数组,将数组排个序。
+朴实无华挨个计算1的数量,最多就是循环n的二进制位数,32位。
-**排序之后,其实每一个数值的下标就代表这前面有几个比它小的了**。
-
-代码如下:
-
-```
-vector vec = nums;
-sort(vec.begin(), vec.end()); // 从小到大排序之后,元素下标就是小于当前数字的数字
-```
-
-此时用一个哈希表hash(本题可以就用一个数组)来做数值和下标的映射。这样就可以通过数值快速知道下标(也就是前面有几个比它小的)。
-
-此时有一个情况,就是数值相同怎么办?
-
-例如,数组:1 2 3 4 4 4 ,第一个数值4的下标是3,第二个数值4的下标是4了。
-
-这里就需要一个技巧了,**在构造数组hash的时候,从后向前遍历,这样hash里存放的就是相同元素最左面的数值和下标了**。
-代码如下:
-
-```CPP
-int hash[101];
-for (int i = vec.size() - 1; i >= 0; i--) { // 从后向前,记录 vec[i] 对应的下标
- hash[vec[i]] = i;
+```C++
+int bitCount(int n) {
+ int count = 0; // 计数器
+ while (n > 0) {
+ if((n & 1) == 1) count++; // 当前位是1,count++
+ n >>= 1 ; // n向右移位
+ }
+ return count;
}
```
-最后在遍历原数组nums,用hash快速找到每一个数值 对应的 小于这个数值的个数。存放在将结果存放在另一个数组中。
+* 方法二
-代码如下:
+这种方法,只循环n的二进制中1的个数次,比方法一高效的多
-```CPP
-// 此时hash里保存的每一个元素数值 对应的 小于这个数值的个数
-for (int i = 0; i < nums.size(); i++) {
- vec[i] = hash[nums[i]];
+```C++
+int bitCount(int n) {
+ int count = 0;
+ while (n) {
+ n &= (n - 1); // 清除最低位的1
+ count++;
+ }
+ return count;
}
```
+以计算12的二进制1的数量为例,如图所示:
-流程如图:
+
-
+下面我就使用方法二,来做这道题目:
-关键地方讲完了,整体C++代码如下:
+## C++代码
-```CPP
+```C++
class Solution {
+private:
+ static int bitCount(int n) { // 计算n的二进制中1的数量
+ int count = 0;
+ while(n) {
+ n &= (n -1); // 清除最低位的1
+ count++;
+ }
+ return count;
+ }
+ static bool cmp(int a, int b) {
+ int bitA = bitCount(a);
+ int bitB = bitCount(b);
+ if (bitA == bitB) return a < b; // 如果bit中1数量相同,比较数值大小
+ return bitA < bitB; // 否则比较bit中1数量大小
+ }
public:
- vector smallerNumbersThanCurrent(vector& nums) {
- vector vec = nums;
- sort(vec.begin(), vec.end()); // 从小到大排序之后,元素下标就是小于当前数字的数字
- int hash[101];
- for (int i = vec.size() - 1; i >= 0; i--) { // 从后向前,记录 vec[i] 对应的下标
- hash[vec[i]] = i;
- }
- // 此时hash里保存的每一个元素数值 对应的 小于这个数值的个数
- for (int i = 0; i < nums.size(); i++) {
- vec[i] = hash[nums[i]];
- }
- return vec;
+ vector sortByBits(vector& arr) {
+ sort(arr.begin(), arr.end(), cmp);
+ return arr;
}
};
```
-可以排序之后加哈希,时间复杂度为O(nlogn)
-
# 其他语言版本
@@ -120,48 +123,8 @@ public:
## Java
```java
-/**
-* 解法一:暴力
-* 时间复杂度:O(n^2)
-* 空间复杂度:O(n)
-*/
-class Solution {
- public int[] smallerNumbersThanCurrent(int[] nums) {
- int[] res = new int[nums.length];
- for (int i = 0; i < nums.length; i++) {
- for (int j = 0; j < nums.length; j++) {
- if (nums[j] < nums[i] && j != i) { // 注意 j 不能和 i 重合
- res[i]++;
- }
- }
- }
- return res;
- }
-}
```
-```java
-/**
-* 优化:排序 + 哈希表
-* 时间复杂度:O(nlogn)
-* 空间复杂度:O(n)
-*/
-class Solution {
- public int[] smallerNumbersThanCurrent(int[] nums) {
- int[] res = Arrays.copyOf(nums, nums.length);
- Arrays.sort(res); // 是对 res 排序,nums 中顺序还要保持
- int[] hash = new int[101]; // 使用哈希表,记录比当前元素小的元素个数
- for (int i = res.length - 1; i >= 0; i--) { // 注意:从后向前
- hash[res[i]] = i; // 排序后,当前下标即表示比当前元素小的元素个数
- }
- // 此时 hash中保存的每一个元素数值 便是 小于这个数值的个数
- for (int i = 0; i < res.length; i++) {
- res[i] = hash[nums[i]];
- }
- return res;
- }
-}
-```
diff --git a/problems/1365.有多少小于当前数字的数字.md b/problems/1365.有多少小于当前数字的数字.md
index 156efea6..5cf6b2d8 100644
--- a/problems/1365.有多少小于当前数字的数字.md
+++ b/problems/1365.有多少小于当前数字的数字.md
@@ -10,14 +10,14 @@
# 1365.有多少小于当前数字的数字
-题目链接:https://leetcode-cn.com/problems/how-many-numbers-are-smaller-than-the-current-number/
+[力扣题目链接](https://leetcode-cn.com/problems/how-many-numbers-are-smaller-than-the-current-number/)
给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。
换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
以数组形式返回答案。
-
+
示例 1:
* 输入:nums = [8,1,2,2,3]
@@ -36,7 +36,7 @@
示例 3:
* 输入:nums = [7,7,7,7]
* 输出:[0,0,0,0]
-
+
提示:
* 2 <= nums.length <= 500
* 0 <= nums[i] <= 100
diff --git a/problems/1382.将二叉搜索树变平衡.md b/problems/1382.将二叉搜索树变平衡.md
index 758d5ad8..bce58c33 100644
--- a/problems/1382.将二叉搜索树变平衡.md
+++ b/problems/1382.将二叉搜索树变平衡.md
@@ -9,7 +9,7 @@
# 1382.将二叉搜索树变平衡
-题目地址:https://leetcode-cn.com/problems/balance-a-binary-search-tree/
+[力扣题目链接](https://leetcode-cn.com/problems/balance-a-binary-search-tree/)
给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。
@@ -35,8 +35,8 @@
这道题目,可以中序遍历把二叉树转变为有序数组,然后在根据有序数组构造平衡二叉搜索树。
建议做这道题之前,先看如下两篇题解:
-* [98.验证二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q) 学习二叉搜索树的特性
-* [108.将有序数组转换为二叉搜索树](https://mp.weixin.qq.com/s/sy3ygnouaZVJs8lhFgl9mw) 学习如何通过有序数组构造二叉搜索树
+* [98.验证二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html) 学习二叉搜索树的特性
+* [108.将有序数组转换为二叉搜索树](https://programmercarl.com/0108.将有序数组转换为二叉搜索树.html) 学习如何通过有序数组构造二叉搜索树
这两道题目做过之后,本题分分钟就可以做出来了。
diff --git a/problems/其他/参与本项目.md b/problems/其他/参与本项目.md
new file mode 100644
index 00000000..69cb8555
--- /dev/null
+++ b/problems/其他/参与本项目.md
@@ -0,0 +1,7 @@
+
+优化已有代码
+
+
+**push代码之前 一定要 先pull最新代码**,否则提交的pr可能会有删除其他录友代码的操作。
+
+一个pr 不要修改过多文件,因为一旦有一个 文件修改有问题,就不能合入,影响其他文件的合入了。