diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 00000000..da03c1c1
Binary files /dev/null and b/.DS_Store differ
diff --git a/README.md b/README.md
index 3b0e8d65..a04f58a6 100644
--- a/README.md
+++ b/README.md
@@ -131,7 +131,7 @@
1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md)
2. [数组:二分查找](./problems/0704.二分查找.md)
3. [数组:移除元素](./problems/0027.移除元素.md)
-4. [数组:序数组的平方](./problems/0977.有序数组的平方.md)
+4. [数组:有序数组的平方](./problems/0977.有序数组的平方.md)
5. [数组:长度最小的子数组](./problems/0209.长度最小的子数组.md)
6. [数组:螺旋矩阵II](./problems/0059.螺旋矩阵II.md)
7. [数组:总结篇](./problems/数组总结篇.md)
diff --git a/problems/.DS_Store b/problems/.DS_Store
new file mode 100644
index 00000000..32266f38
Binary files /dev/null and b/problems/.DS_Store differ
diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md
index fc222441..4e01926f 100644
--- a/problems/0028.实现strStr.md
+++ b/problems/0028.实现strStr.md
@@ -174,9 +174,11 @@ next数组就是一个前缀表(prefix table)。
长度为前1个字符的子串`a`,最长相同前后缀的长度为0。(注意字符串的**前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串**;**后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串**。)
+
长度为前2个字符的子串`aa`,最长相同前后缀的长度为1。
+
长度为前3个字符的子串`aab`,最长相同前后缀的长度为0。
以此类推:
diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md
index e8dd3690..ac6f20f9 100644
--- a/problems/0042.接雨水.md
+++ b/problems/0042.接雨水.md
@@ -471,7 +471,7 @@ class Solution {
### Python:
双指针法
-```python3
+```Python
class Solution:
def trap(self, height: List[int]) -> int:
res = 0
@@ -510,7 +510,7 @@ class Solution:
return result
```
单调栈
-```python3
+```Python
class Solution:
def trap(self, height: List[int]) -> int:
# 单调栈
diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md
index 05ad872b..7dbf531b 100644
--- a/problems/0045.跳跃游戏II.md
+++ b/problems/0045.跳跃游戏II.md
@@ -73,11 +73,11 @@ public:
for (int i = 0; i < nums.size(); i++) {
nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖最远距离下标
if (i == curDistance) { // 遇到当前覆盖最远距离下标
- if (curDistance != nums.size() - 1) { // 如果当前覆盖最远距离下标不是终点
+ if (curDistance < nums.size() - 1) { // 如果当前覆盖最远距离下标不是终点
ans++; // 需要走下一步
curDistance = nextDistance; // 更新当前覆盖最远距离下标(相当于加油了)
if (nextDistance >= nums.size() - 1) break; // 下一步的覆盖范围已经可以达到终点,结束循环
- } else break; // 当前覆盖最远距离下标是集合终点,不用做ans++操作了,直接结束
+ } else break; // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束
}
}
return ans;
@@ -126,7 +126,7 @@ public:
可以看出版本二的代码相对于版本一简化了不少!
-其精髓在于控制移动下标i只移动到nums.size() - 2的位置,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。
+**其精髓在于控制移动下标i只移动到nums.size() - 2的位置**,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。
## 总结
diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md
index 665710a9..14017f98 100644
--- a/problems/0053.最大子序和.md
+++ b/problems/0053.最大子序和.md
@@ -12,9 +12,9 @@
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
-输入: [-2,1,-3,4,-1,2,1,-5,4]
-输出: 6
-解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
+* 输入: [-2,1,-3,4,-1,2,1,-5,4]
+* 输出: 6
+* 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
## 暴力解法
@@ -103,8 +103,28 @@ public:
当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。
+
+## 常见误区
+
+误区一:
+
不少同学认为 如果输入用例都是-1,或者 都是负数,这个贪心算法跑出来的结果是0, 这是**又一次证明脑洞模拟不靠谱的经典案例**,建议大家把代码运行一下试一试,就知道了,也会理解 为什么 result 要初始化为最小负数了。
+
+误区二:
+
+大家在使用贪心算法求解本题,经常陷入的误区,就是分不清,是遇到 负数就选择起始位置,还是连续和为负选择起始位置。
+
+在动画演示用,大家可以发现, 4,遇到 -1 的时候,我们依然累加了,为什么呢?
+
+因为和为3,只要连续和还是正数就会 对后面的元素 起到增大总和的作用。 所以只要连续和为正数我们就保留。
+
+这里也会有录友疑惑,那 4 + -1 之后 不就变小了吗? 会不会错过 4 成为最大连续和的可能性?
+
+其实并不会,因为还有一个变量result 一直在更新 最大的连续和,只要有更大的连续和出现,result就更新了,那么result已经把4更新了,后面 连续和变成3,也不会对最后结果有影响。
+
+
+
## 动态规划
当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的dp方法。
@@ -135,7 +155,7 @@ public:
本题的贪心思路其实并不好想,这也进一步验证了,别看贪心理论很直白,有时候看似是常识,但贪心的题目一点都不简单!
-后续将介绍的贪心题目都挺难的,哈哈,所以贪心很有意思,别小看贪心!
+后续将介绍的贪心题目都挺难的,所以贪心很有意思,别小看贪心!
## 其他语言版本
diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md
index 7584e952..7b02075b 100644
--- a/problems/0055.跳跃游戏.md
+++ b/problems/0055.跳跃游戏.md
@@ -78,7 +78,7 @@ public:
一些同学可能感觉,我在讲贪心系列的时候,题目和题目之间貌似没有什么联系?
-**是真的就是没什么联系,因为贪心无套路!**没有个整体的贪心框架解决一系列问题,只能是接触各种类型的题目锻炼自己的贪心思维!
+**是真的就是没什么联系,因为贪心无套路**!没有个整体的贪心框架解决一系列问题,只能是接触各种类型的题目锻炼自己的贪心思维!
## 其他语言版本
diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md
index a34439e6..8a877d20 100644
--- a/problems/0072.编辑距离.md
+++ b/problems/0072.编辑距离.md
@@ -20,24 +20,20 @@
* 输入:word1 = "horse", word2 = "ros"
* 输出:3
* 解释:
-```
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
-``
* 示例 2:
* 输入:word1 = "intention", word2 = "execution"
* 输出:5
* 解释:
-```
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')
-```
提示:
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md
index 97178cd5..25d9e84b 100644
--- a/problems/0093.复原IP地址.md
+++ b/problems/0093.复原IP地址.md
@@ -40,6 +40,9 @@
* 0 <= s.length <= 3000
* s 仅由数字组成
+# 算法公开课
+
+**《代码随想录》算法视频公开课:[93.复原IP地址](https://www.bilibili.com/video/BV1XP4y1U73i/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
# 思路
@@ -424,6 +427,30 @@ class Solution:
return True
```
+python3; 简单拼接版本(类似Leetcode131写法):
+```python
+class Solution:
+ def restoreIpAddresses(self, s: str) -> List[str]:
+ global results, path
+ results = []
+ path = []
+ self.backtracking(s,0)
+ return results
+
+ def backtracking(self,s,index):
+ global results,path
+ if index == len(s) and len(path)==4:
+ results.append('.'.join(path)) # 在连接时需要中间间隔符号的话就在''中间写上对应的间隔符
+ return
+ for i in range(index,len(s)):
+ if len(path)>3: break # 剪枝
+ temp = s[index:i+1]
+ if (int(temp)<256 and int(temp)>0 and temp[0]!='0') or (temp=='0'):
+ path.append(temp)
+ self.backtracking(s,i+1)
+ path.pop()
+```
+
## Go
```go
diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md
index 8ae7ee79..36ae1ec6 100644
--- a/problems/0102.二叉树的层序遍历.md
+++ b/problems/0102.二叉树的层序遍历.md
@@ -23,10 +23,12 @@
* 111.二叉树的最小深度
+

+
# 102.二叉树的层序遍历
[力扣题目链接](https://leetcode.cn/problems/binary-tree-level-order-traversal/)
@@ -2532,20 +2534,18 @@ class Solution:
return 0
queue_ = [root]
- result = []
+ depth = 0
while queue_:
length = len(queue_)
- sub = []
for i in range(length):
cur = queue_.pop(0)
sub.append(cur.val)
#子节点入队列
if cur.left: queue_.append(cur.left)
if cur.right: queue_.append(cur.right)
- result.append(sub)
+ depth += 1
-
- return len(result)
+ return depth
```
Go:
diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md
index f8109f85..c2b2872b 100644
--- a/problems/0106.从中序与后序遍历序列构造二叉树.md
+++ b/problems/0106.从中序与后序遍历序列构造二叉树.md
@@ -397,6 +397,9 @@ public:
};
```
+## Python
+
+
# 105.从前序与中序遍历序列构造二叉树
[力扣题目链接](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/)
@@ -650,6 +653,37 @@ class Solution {
```
## Python
+```python
+class Solution:
+ def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
+ # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
+ if not postorder:
+ return
+
+ # 第二步: 后序遍历的最后一个就是当前的中间节点
+ root_val = postorder[-1]
+ root = TreeNode(root_val)
+
+ # 第三步: 找切割点.
+ root_index = inorder.index(root_val)
+
+ # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
+ left_inorder = inorder[:root_index]
+ right_inorder = inorder[root_index + 1:]
+
+ # 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
+ # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
+ left_postorder = postorder[:len(left_inorder)]
+ right_postorder = postorder[len(left_inorder): len(postorder) - 1]
+
+
+ # 第六步: 递归
+ root.left = self.buildTree(left_inorder, left_postorder)
+ root.right = self.buildTree(right_inorder, right_postorder)
+
+ # 第七步: 返回答案
+ return root
+```
105.从前序与中序遍历序列构造二叉树
diff --git a/problems/0130.被围绕的区域.md b/problems/0130.被围绕的区域.md
index 528d2042..c2aa5696 100644
--- a/problems/0130.被围绕的区域.md
+++ b/problems/0130.被围绕的区域.md
@@ -83,6 +83,7 @@ public:
```
## 其他语言版本
+
参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md
index ade84773..192e58a6 100644
--- a/problems/0134.加油站.md
+++ b/problems/0134.加油站.md
@@ -88,7 +88,7 @@ public:
* 情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的
* 情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。
-* 情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点。
+* 情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。
C++代码如下:
diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md
index 176ea687..f0323bc4 100644
--- a/problems/0150.逆波兰表达式求值.md
+++ b/problems/0150.逆波兰表达式求值.md
@@ -163,6 +163,25 @@ class Solution {
python3
+```python
+from operator import add, sub, mul
+
+class Solution:
+ op_map = {'+': add, '-': sub, '*': mul, '/': lambda x, y: int(x / y)}
+
+ def evalRPN(self, tokens: List[str]) -> int:
+ stack = []
+ for token in tokens:
+ if token not in {'+', '-', '*', '/'}:
+ stack.append(int(token))
+ else:
+ op2 = stack.pop()
+ op1 = stack.pop()
+ stack.append(self.op_map[token](op1, op2)) # 第一个出来的在运算符后面
+ return stack.pop()
+```
+
+另一种可行,但因为使用eval相对较慢的方法:
```python
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md
index a12d8f76..dc12ae23 100644
--- a/problems/0151.翻转字符串里的单词.md
+++ b/problems/0151.翻转字符串里的单词.md
@@ -442,7 +442,7 @@ class Solution:
while left <= right and s[left] == ' ': #去除开头的空格
left += 1
while left <= right and s[right] == ' ': #去除结尾的空格
- right = right-1
+ right -= 1
tmp = []
while left <= right: #去除单词中间多余的空格
if s[left] != ' ':
diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md
index b87877c9..10ac8264 100644
--- a/problems/0222.完全二叉树的节点个数.md
+++ b/problems/0222.完全二叉树的节点个数.md
@@ -188,7 +188,7 @@ public:
```CPP
if (root == nullptr) return 0;
-// 开始根据做深度和有深度是否相同来判断该子树是不是满二叉树
+// 开始根据左深度和右深度是否相同来判断该子树是不是满二叉树
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
@@ -843,3 +843,4 @@ impl Solution {
+
diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md
index 4983c93a..efeb1046 100644
--- a/problems/0232.用栈实现队列.md
+++ b/problems/0232.用栈实现队列.md
@@ -38,7 +38,7 @@ queue.empty(); // 返回 false
## 思路
-《代码随想录》算法公开课:[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对链表的理解。
+《代码随想录》算法公开课:[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对栈和队列的理解。
这是一道模拟题,不涉及到具体算法,考察的就是对栈和队列的掌握程度。
@@ -662,3 +662,4 @@ impl MyQueue {
+
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index 2d796671..d0c190a0 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -468,7 +468,7 @@ class Solution {
---
## Python:
递归法+隐形回溯
-```Python3
+```Python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
@@ -499,7 +499,7 @@ class Solution:
迭代法:
-```python3
+```Python
from collections import deque
diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md
index 2e98ef6f..6f5a34e7 100644
--- a/problems/0349.两个数组的交集.md
+++ b/problems/0349.两个数组的交集.md
@@ -137,8 +137,18 @@ class Solution {
resSet.add(i);
}
}
- //将结果几何转为数组
+
+ //方法1:直接将结果几何转为数组
return resSet.stream().mapToInt(x -> x).toArray();
+
+ //方法2:另外申请一个数组存放setRes中的元素,最后返回数组
+ int[] arr = new int[setRes.size()];
+ int j = 0;
+ for(int i : setRes){
+ arr[j++] = i;
+ }
+
+ return arr;
}
}
```
@@ -423,3 +433,4 @@ C#:
+
diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md
index 723d1d9a..efb9c6b6 100644
--- a/problems/0376.摆动序列.md
+++ b/problems/0376.摆动序列.md
@@ -53,21 +53,64 @@
**实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)**
-**这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点**。
+**这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点**
-本题代码实现中,还有一些技巧,例如统计峰值的时候,数组最左面和最右面是最不好统计的。
+在计算是否有峰值的时候,大家知道遍历的下标i ,计算prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果`prediff < 0 && curdiff > 0` 或者 `prediff > 0 && curdiff < 0` 此时就有波动就需要统计。
-例如序列[2,5],它的峰值数量是2,如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。
+这是我们思考本题的一个大题思路,但本题要考虑三种情况:
-所以可以针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0,如图:
+1. 情况一:上下坡中有平坡
+2. 情况二:数组首尾两端
+3. 情况三:单调坡中有平坡
+
+### 情况一:上下坡中有平坡
+
+例如 [1,2,2,2,1]这样的数组,如图:
+
+
+
+它的摇摆序列长度是多少呢? **其实是长度是3**,也就是我们在删除的时候 要不删除左面的三个2,要不就删除右边的三个2。
+
+如图,可以统一规则,删除左边的三个2:
+
+
+
+在图中,当i指向第一个2的时候,`prediff > 0 && curdiff = 0` ,当 i 指向最后一个2的时候 `prediff = 0 && curdiff < 0`。
+
+如果我们采用,删左面三个2的规则,那么 当 `prediff = 0 && curdiff < 0` 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。
+
+所以我们记录峰值的条件应该是: `(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)`,为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。
+
+
+### 情况二:数组首尾两端
+
+
+所以本题统计峰值的时候,数组最左面和最右面如果统计呢?
+
+题目中说了,如果只有两个不同的元素,那摆动序列也是2。
+
+例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。
+
+因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。
+
+这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为2。
+
+不写死的话,如果和我们的判断规则结合在一起呢?
+
+可以假设,数组最前面还有一个数字,那这个数字应该是什么呢?
+
+之前我们在 讨论 情况一:相同数字连续 的时候, prediff = 0 ,curdiff < 0 或者 >0 也记为波谷。
+
+那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0,如图:

针对以上情形,result初始为1(默认最右面有一个峰值),此时curDiff > 0 && preDiff <= 0,那么result++(计算了左面的峰值),最后得到的result就是2(峰值个数为2即摆动序列长度为2)
-C++代码如下(和上图是对应的逻辑):
+经过以上分析后,我们可以写出如下代码:
-```CPP
+```CPP
+// 版本一
class Solution {
public:
int wiggleMaxLength(vector
+
diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md
index 3cb9d3db..8d4b97f1 100644
--- a/problems/0538.把二叉搜索树转换为累加树.md
+++ b/problems/0538.把二叉搜索树转换为累加树.md
@@ -209,29 +209,28 @@ class Solution {
# self.right = right
class Solution:
def __init__(self):
- self.pre = TreeNode()
+ self.count = 0
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
+ if root == None:
+ return
'''
倒序累加替换:
- [2, 5, 13] -> [[2]+[1]+[0], [2]+[1], [2]] -> [20, 18, 13]
'''
- self.traversal(root)
- return root
-
- def traversal(self, root: TreeNode) -> None:
- # 因为要遍历整棵树,所以递归函数不需要返回值
- # Base Case
- if not root:
- return None
- # 单层递归逻辑:中序遍历的反译 - 右中左
- self.traversal(root.right) # 右
+ # 右
+ self.convertBST(root.right)
+ # 中
# 中节点:用当前root的值加上pre的值
- root.val += self.pre.val # 中
- self.pre = root
+ self.count += root.val
- self.traversal(root.left) # 左
+ root.val = self.count
+
+ # 左
+ self.convertBST(root.left)
+
+ return root
+
```
## Go
diff --git a/problems/0827.最大人工岛.md b/problems/0827.最大人工岛.md
index fb0c797e..05d82f7e 100644
--- a/problems/0827.最大人工岛.md
+++ b/problems/0827.最大人工岛.md
@@ -3,8 +3,11 @@