diff --git a/README.md b/README.md
index c006fd6b..022a45e8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## 一些闲话:
+👉 推荐 [在线阅读](http://programmercarl.com/) (Github在国内访问经常不稳定)
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
> 2. **PDF版本** : [「代码随想录」算法精讲 PDF 版本](https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ) 。
@@ -119,30 +119,40 @@
* [递归算法的时间与空间复杂度分析!](./problems/前序/递归算法的时间与空间复杂度分析.md)
* [刷了这么多题,你了解自己代码的内存消耗么?](./problems/前序/刷了这么多题,你了解自己代码的内存消耗么?.md)
-(持续更新中.....)
+
+## 社群
+
+* [准备秋招的录友们,组织在这里!](https://mp.weixin.qq.com/s/xX4LFwZQIG_XiQAxVBrfeA)
+* [准备社招的录友们,组织在这里!](https://mp.weixin.qq.com/s/mbQ3s17ZJ4LXFRb-VD58Ww)
## 知识星球精选
-1. [选择方向的时候,我也迷茫了](https://mp.weixin.qq.com/s/ZCzFiAHZHLqHPLJQXNm75g)
-2. [刷题就用库函数了,怎么了?](https://mp.weixin.qq.com/s/6K3_OSaudnHGq2Ey8vqYfg)
-3. [关于实习,大家可能有点迷茫!](https://mp.weixin.qq.com/s/xcxzi7c78kQGjvZ8hh7taA)
-4. [马上秋招了,慌得很!](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
-5. [Carl看了上百份简历,总结了这些!](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
-6. [面试中遇到了发散性问题.....](https://mp.weixin.qq.com/s/SSonDxi2pjkSVwHNzZswng)
-7. [英语到底重不重要!](https://mp.weixin.qq.com/s/1PRZiyF_-TVA-ipwDNjdKw)
-8. [计算机专业要不要读研!](https://mp.weixin.qq.com/s/c9v1L3IjqiXtkNH7sOMAdg)
-9. [秋招和提前批都越来越提前了....](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
-10. [你的简历里「专业技能」写的够专业么?](https://mp.weixin.qq.com/s/bp6y-e5FVN28H9qc8J9zrg)
-11. [对于秋招,实习生也有烦恼....](https://mp.weixin.qq.com/s/ka07IPryFnfmIjByFFcXDg)
-12. [华为提前批已经开始了.....](https://mp.weixin.qq.com/s/OC35QDG8pn5OwLpCxieStw)
-13. [大厂新人培养体系应该是什么样的?](https://mp.weixin.qq.com/s/WBaPCosOljB5NEkFL2GhOQ)
+* [HR面注意事项](https://mp.weixin.qq.com/s/0mDyCyCBfa0DeGov3Pebnw)
+* [刷题攻略要刷两遍!](https://mp.weixin.qq.com/s/e3_L7FZglY4UlTVvKolZyQ)
+* [秋招进行中的迷茫与焦虑......](https://mp.weixin.qq.com/s/X15MUw4sfH_AQNHdAivEvg)
+* [大厂新人培养体系应该是什么样的?](https://mp.weixin.qq.com/s/WBaPCosOljB5NEkFL2GhOQ)
+* [你的简历里「专业技能」写的够专业么?](https://mp.weixin.qq.com/s/bp6y-e5FVN28H9qc8J9zrg)
+* [Carl看了上百份简历,总结了这些!](https://mp.weixin.qq.com/s/sJa87MZD28piCOVMFkIbwQ)
+* [备战2022届秋招](https://mp.weixin.qq.com/s/7q7W8Cb2-a5U5atZdOnOFA)
+* [技术不太好,如果选择方向](https://mp.weixin.qq.com/s/ZCzFiAHZHLqHPLJQXNm75g)
+* [刷题要不要使用库函数](https://mp.weixin.qq.com/s/6K3_OSaudnHGq2Ey8vqYfg)
+* [关于实习的几点问题](https://mp.weixin.qq.com/s/xcxzi7c78kQGjvZ8hh7taA)
+* [面试中遇到了发散性问题,怎么帮?](https://mp.weixin.qq.com/s/SSonDxi2pjkSVwHNzZswng)
+* [英语到底重不重要!](https://mp.weixin.qq.com/s/1PRZiyF_-TVA-ipwDNjdKw)
+* [计算机专业要不要读研!](https://mp.weixin.qq.com/s/c9v1L3IjqiXtkNH7sOMAdg)
+* [关于提前批的一些建议](https://mp.weixin.qq.com/s/SNFiRDx8CKyjhTPlys6ywQ)
+* [已经在实习的录友要如何准备秋招](https://mp.weixin.qq.com/s/ka07IPryFnfmIjByFFcXDg)
+* [华为提前批已经开始了](https://mp.weixin.qq.com/s/OC35QDG8pn5OwLpCxieStw)
## 杂谈
+* [「代码随想录」刷题网站上线](https://mp.weixin.qq.com/s/-6rd_g7LrVD1fuKBYk2tXQ)。
* [LeetCode-Master上榜了](https://mp.weixin.qq.com/s/wZRTrA9Rbvgq1yEkSw4vfQ)
+* [上榜之后,都有哪些变化?](https://mp.weixin.qq.com/s/VJBV0qSBthjnbbmW-lctLA)
* [大半年过去了......](https://mp.weixin.qq.com/s/lubfeistPxBLSQIe5XYg5g)
* [一万录友在B站学算法!](https://mp.weixin.qq.com/s/Vzq4zkMZY7erKeu0fqGLgw)
+
## 数组
1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md)
@@ -241,7 +251,7 @@
15. [二叉树:以为使用了递归,其实还隐藏着回溯](./problems/二叉树中递归带着回溯.md)
16. [二叉树:做了这么多题目了,我的左叶子之和是多少?](./problems/0404.左叶子之和.md)
17. [二叉树:我的左下角的值是多少?](./problems/0513.找树左下角的值.md)
-18. [二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](./problems/0112.路径总和.md)
+18. [二叉树:路径总和](./problems/0112.路径总和.md)
19. [二叉树:构造二叉树登场!](./problems/0106.从中序与后序遍历序列构造二叉树.md)
20. [二叉树:构造一棵最大的二叉树](./problems/0654.最大二叉树.md)
21. [本周小结!(二叉树系列三)](./problems/周总结/20201010二叉树周末总结.md)
@@ -409,6 +419,7 @@
2. [单调栈:下一个更大元素I](./problems/0496.下一个更大元素I.md)
3. [单调栈:下一个更大元素II](./problems/0503.下一个更大元素II.md)
4. [单调栈:接雨水](./problems/0042.接雨水.md)
+5. [单调栈:柱状图中最大的矩形](./problems/0084.柱状图中最大的矩形.md)
(持续更新中....)
@@ -451,7 +462,6 @@
* [24.两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md)
* [234.回文链表](./problems/0234.回文链表.md)
* [143.重排链表](./problems/0143.重排链表.md)【数组】【双向队列】【直接操作链表】
-* [234.回文链表](./problems/0234.回文链表.md)
* [141.环形链表](./problems/0141.环形链表.md)
## 哈希表
diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md
index 5be94996..fd17af62 100644
--- a/problems/0001.两数之和.md
+++ b/problems/0001.两数之和.md
@@ -9,7 +9,7 @@
## 1. 两数之和
-https://leetcode-cn.com/problems/two-sum/
+[力扣题目链接](https://leetcode-cn.com/problems/two-sum/)
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
@@ -29,10 +29,10 @@ https://leetcode-cn.com/problems/two-sum/
很明显暴力的解法是两层for循环查找,时间复杂度是O(n^2)。
建议大家做这道题目之前,先做一下这两道
-* [242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)
-* [349. 两个数组的交集](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q)
+* [242. 有效的字母异位词](https://www.programmercarl.com/0242.有效的字母异位词.html)
+* [349. 两个数组的交集](https://www.programmercarl.com/0349.两个数组的交集.html)
-[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA) 这道题目是用数组作为哈希表来解决哈希问题,[349. 两个数组的交集](https://mp.weixin.qq.com/s/aMSA5zrp3jJcLjuSB0Es2Q)这道题目是通过set作为哈希表来解决哈希问题。
+[242. 有效的字母异位词](https://www.programmercarl.com/0242.有效的字母异位词.html) 这道题目是用数组作为哈希表来解决哈希问题,[349. 两个数组的交集](https://www.programmercarl.com/0349.两个数组的交集.html)这道题目是通过set作为哈希表来解决哈希问题。
本题呢,则要使用map,那么来看一下使用数组和set来做哈希法的局限。
@@ -51,7 +51,7 @@ C++中map,有三种类型:
std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。
-同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。 更多哈希表的理论知识请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。
+同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。 更多哈希表的理论知识请看[关于哈希表,你该了解这些!](https://www.programmercarl.com/哈希表理论基础.html)。
**这道题目中并不需要key有序,选择std::unordered_map 效率更高!**
@@ -62,7 +62,7 @@ std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底
C++代码:
-```C++
+```CPP
class Solution {
public:
vector twoSum(vector& nums, int target) {
@@ -110,13 +110,14 @@ Python:
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
- hashmap={}
- for ind,num in enumerate(nums):
- hashmap[num] = ind
- for i,num in enumerate(nums):
- j = hashmap.get(target - num)
- if j is not None and i!=j:
- return [i,j]
+ records = dict()
+
+ # 用枚举更方便,就不需要通过索引再去取当前位置的值
+ for idx, val in enumerate(nums):
+ if target - val not in records:
+ records[val] = idx
+ else:
+ return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
```
@@ -210,4 +211,4 @@ function twoSum(array $nums, int $target): array
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0005.最长回文子串.md b/problems/0005.最长回文子串.md
index 0063b358..de20feeb 100644
--- a/problems/0005.最长回文子串.md
+++ b/problems/0005.最长回文子串.md
@@ -67,7 +67,7 @@
以上三种情况分析完了,那么递归公式如下:
-```C++
+```CPP
if (s[i] == s[j]) {
if (j - i <= 1) { // 情况一 和 情况二
dp[i][j] = true;
@@ -81,7 +81,7 @@ if (s[i] == s[j]) {
在得到[i,j]区间是否是回文子串的时候,直接保存最长回文子串的左边界和右边界,代码如下:
-```C++
+```CPP
if (s[i] == s[j]) {
if (j - i <= 1) { // 情况一 和 情况二
dp[i][j] = true;
@@ -120,7 +120,7 @@ dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:
代码如下:
-```C++
+```CPP
for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
for (int j = i; j < s.size(); j++) {
if (s[i] == s[j]) {
@@ -150,7 +150,7 @@ for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
以上分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
string longestPalindrome(string s) {
@@ -181,7 +181,7 @@ public:
```
以上代码是为了凸显情况一二三,当然是可以简洁一下的,如下:
-```C++
+```CPP
class Solution {
public:
string longestPalindrome(string s) {
@@ -226,7 +226,7 @@ public:
**这两种情况可以放在一起计算,但分别计算思路更清晰,我倾向于分别计算**,代码如下:
-```C++
+```CPP
class Solution {
public:
int left = 0;
@@ -270,6 +270,23 @@ public:
## Python
```python
+class Solution:
+ def longestPalindrome(self, s: str) -> str:
+ dp = [[False] * len(s) for _ in range(len(s))]
+ maxlenth = 0
+ left = 0
+ right = 0
+ for i in range(len(s) - 1, -1, -1):
+ for j in range(i, len(s)):
+ if s[j] == s[i]:
+ if j - i <= 1 or dp[i + 1][j - 1]:
+ dp[i][j] = True
+ if dp[i][j] and j - i + 1 > maxlenth:
+ maxlenth = j - i + 1
+ left = i
+ right = j
+ return s[left:right + 1]
+
```
## Go
@@ -286,6 +303,6 @@ public:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md
index 36abb58c..9a3a8d5b 100644
--- a/problems/0015.三数之和.md
+++ b/problems/0015.三数之和.md
@@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/3sum/
大家可以尝试使用哈希法写一写,就知道其困难的程度了。
哈希法C++代码:
-```C++
+```CPP
class Solution {
public:
vector> threeSum(vector& nums) {
@@ -107,7 +107,7 @@ public:
C++代码代码如下:
-```C++
+```CPP
class Solution {
public:
vector> threeSum(vector& nums) {
@@ -399,4 +399,4 @@ function threeSum(array $nums): array
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md
index 1562052c..7aa72e1b 100644
--- a/problems/0017.电话号码的字母组合.md
+++ b/problems/0017.电话号码的字母组合.md
@@ -416,4 +416,4 @@ var letterCombinations = function(digits) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md
index 0caf12be..75cd9e8e 100644
--- a/problems/0018.四数之和.md
+++ b/problems/0018.四数之和.md
@@ -67,7 +67,7 @@ https://leetcode-cn.com/problems/4sum/
C++代码
-```C++
+```CPP
class Solution {
public:
vector> fourSum(vector& nums, int target) {
@@ -201,6 +201,54 @@ class Solution(object):
```
Go:
+```go
+func fourSum(nums []int, target int) [][]int {
+ if len(nums) < 4 {
+ return nil
+ }
+ sort.Ints(nums)
+ var res [][]int
+ for i := 0; i < len(nums)-3; i++ {
+ n1 := nums[i]
+ // if n1 > target { // 不能这样写,因为可能是负数
+ // break
+ // }
+ if i > 0 && n1 == nums[i-1] {
+ continue
+ }
+ for j := i + 1; j < len(nums)-2; j++ {
+ n2 := nums[j]
+ if j > i+1 && n2 == nums[j-1] {
+ continue
+ }
+ l := j + 1
+ r := len(nums) - 1
+ for l < r {
+ n3 := nums[l]
+ n4 := nums[r]
+ sum := n1 + n2 + n3 + n4
+ if sum < target {
+ l++
+ } else if sum > target {
+ r--
+ } else {
+ res = append(res, []int{n1, n2, n3, n4})
+ for l < r && n3 == nums[l+1] { // 去重
+ l++
+ }
+ for l < r && n4 == nums[r-1] { // 去重
+ r--
+ }
+ // 找到答案时,双指针同时靠近
+ r--
+ l++
+ }
+ }
+ }
+ }
+ return res
+}
+```
javaScript:
@@ -241,4 +289,4 @@ var fourSum = function(nums, target) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md
index 52735794..3e1a682c 100644
--- a/problems/0019.删除链表的倒数第N个节点.md
+++ b/problems/0019.删除链表的倒数第N个节点.md
@@ -58,7 +58,7 @@
此时不难写出如下C++代码:
-```C++
+```CPP
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
@@ -184,9 +184,28 @@ var removeNthFromEnd = function(head, n) {
return ret.next;
};
```
+Kotlin:
+```Kotlin
+fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
+ val pre = ListNode(0).apply {
+ this.next = head
+ }
+ var fastNode: ListNode? = pre
+ var slowNode: ListNode? = pre
+ for (i in 0..n) {
+ fastNode = fastNode?.next
+ }
+ while (fastNode != null) {
+ slowNode = slowNode?.next
+ fastNode = fastNode.next
+ }
+ slowNode?.next = slowNode?.next?.next
+ return pre.next
+}
+```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md
index 178bc6f8..a26aa308 100644
--- a/problems/0020.有效的括号.md
+++ b/problems/0020.有效的括号.md
@@ -108,7 +108,7 @@ cd a/b/c/../../
实现C++代码如下:
-```C++
+```CPP
class Solution {
public:
bool isValid(string s) {
@@ -264,4 +264,4 @@ var isValid = function(s) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md
index 66e149e6..91e566dd 100644
--- a/problems/0024.两两交换链表中的节点.md
+++ b/problems/0024.两两交换链表中的节点.md
@@ -43,7 +43,7 @@ https://leetcode-cn.com/problems/swap-nodes-in-pairs/
对应的C++代码实现如下: (注释中详细和如上图中的三步做对应)
-```C++
+```CPP
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
@@ -86,6 +86,34 @@ public:
## 其他语言版本
+C:
+```
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ * int val;
+ * struct ListNode *next;
+ * };
+ */
+
+
+struct ListNode* swapPairs(struct ListNode* head){
+ //使用双指针避免使用中间变量
+ typedef struct ListNode ListNode;
+ ListNode *fakehead = (ListNode *)malloc(sizeof(ListNode));
+ fakehead->next = head;
+ ListNode* right = fakehead->next;
+ ListNode* left = fakehead;
+ while(left && right && right->next ){
+ left->next = right->next;
+ right->next = left->next->next;
+ left->next->next = right;
+ left = right;
+ right = left->next;
+ }
+ return fakehead->next;
+}
+```
Java:
@@ -200,9 +228,30 @@ var swapPairs = function (head) {
};
```
+Kotlin:
+
+```kotlin
+fun swapPairs(head: ListNode?): ListNode? {
+ val dummyNode = ListNode(0).apply {
+ this.next = head
+ }
+ var cur: ListNode? = dummyNode
+ while (cur?.next != null && cur.next?.next != null) {
+ val temp = cur.next
+ val temp2 = cur.next?.next?.next
+ cur.next = cur.next?.next
+ cur.next?.next = temp
+ cur.next?.next?.next = temp2
+ cur = cur.next?.next
+ }
+ return dummyNode.next
+}
+```
+
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md
index f1187db7..3819d6a5 100644
--- a/problems/0027.移除元素.md
+++ b/problems/0027.移除元素.md
@@ -48,7 +48,7 @@
代码如下:
-```C++
+```CPP
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
@@ -85,7 +85,7 @@ public:
后序都会一一介绍到,本题代码如下:
-```C++
+```CPP
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
@@ -216,8 +216,27 @@ fn main() {
println!("{:?}",remove_element(&mut nums, 5));
}
```
+
+Swift:
+
+```swift
+func removeElement(_ nums: inout [Int], _ val: Int) -> Int {
+ var slowIndex = 0
+
+ for fastIndex in 0..
+
diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md
index 69f8c9d6..4fb418f0 100644
--- a/problems/0028.实现strStr.md
+++ b/problems/0028.实现strStr.md
@@ -315,7 +315,7 @@ next[i] = j;
最后整体构建next数组的函数代码如下:
-```C++
+```CPP
void getNext(int* next, const string& s){
int j = -1;
next[0] = j;
@@ -386,7 +386,7 @@ if (j == (t.size() - 1) ) {
那么使用next数组,用模式串匹配文本串的整体代码如下:
-```C++
+```CPP
int j = -1; // 因为next数组里记录的起始位置为-1
for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
while(j >= 0 && s[i] != t[j + 1]) { // 不匹配
@@ -405,7 +405,7 @@ for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
# 前缀表统一减一 C++代码实现
-```C++
+```CPP
class Solution {
public:
void getNext(int* next, const string& s) {
@@ -457,7 +457,7 @@ public:
我给出的getNext的实现为:(前缀表统一减一)
-```C++
+```CPP
void getNext(int* next, const string& s) {
int j = -1;
next[0] = j;
@@ -479,7 +479,7 @@ void getNext(int* next, const string& s) {
那么前缀表不减一来构建next数组,代码如下:
-```C++
+```CPP
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;
@@ -502,7 +502,7 @@ void getNext(int* next, const string& s) {
实现代码如下:
-```C++
+```CPP
class Solution {
public:
void getNext(int* next, const string& s) {
@@ -808,7 +808,93 @@ func strStr(haystack string, needle string) int {
}
```
+JavaScript版本
+> 前缀表统一减一
+
+```javascript
+/**
+ * @param {string} haystack
+ * @param {string} needle
+ * @return {number}
+ */
+var strStr = function (haystack, needle) {
+ if (needle.length === 0)
+ return 0;
+
+ const getNext = (needle) => {
+ let next = [];
+ let j = -1;
+ next.push(j);
+
+ for (let i = 1; i < needle.length; ++i) {
+ while (j >= 0 && needle[i] !== needle[j + 1])
+ j = next[j];
+ if (needle[i] === needle[j + 1])
+ j++;
+ next.push(j);
+ }
+
+ return next;
+ }
+
+ let next = getNext(needle);
+ let j = -1;
+ for (let i = 0; i < haystack.length; ++i) {
+ while (j >= 0 && haystack[i] !== needle[j + 1])
+ j = next[j];
+ if (haystack[i] === needle[j + 1])
+ j++;
+ if (j === needle.length - 1)
+ return (i - needle.length + 1);
+ }
+
+ return -1;
+};
+```
+
+> 前缀表统一不减一
+
+```javascript
+/**
+ * @param {string} haystack
+ * @param {string} needle
+ * @return {number}
+ */
+var strStr = function (haystack, needle) {
+ if (needle.length === 0)
+ return 0;
+
+ const getNext = (needle) => {
+ let next = [];
+ let j = 0;
+ next.push(j);
+
+ for (let i = 1; i < needle.length; ++i) {
+ while (j > 0 && needle[i] !== needle[j])
+ j = next[j - 1];
+ if (needle[i] === needle[j])
+ j++;
+ next.push(j);
+ }
+
+ return next;
+ }
+
+ let next = getNext(needle);
+ let j = 0;
+ for (let i = 0; i < haystack.length; ++i) {
+ while (j > 0 && haystack[i] !== needle[j])
+ j = next[j - 1];
+ if (haystack[i] === needle[j])
+ j++;
+ if (j === needle.length)
+ return (i - needle.length + 1);
+ }
+
+ return -1;
+};
+```
@@ -816,4 +902,4 @@ func strStr(haystack string, needle string) int {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0031.下一个排列.md b/problems/0031.下一个排列.md
index fbe31eb3..10ac9df4 100644
--- a/problems/0031.下一个排列.md
+++ b/problems/0031.下一个排列.md
@@ -75,7 +75,7 @@
对应的C++代码如下:
-```C++
+```CPP
class Solution {
public:
void nextPermutation(vector& nums) {
@@ -99,6 +99,24 @@ public:
## Java
```java
+class Solution {
+ public void nextPermutation(int[] nums) {
+ for (int i = nums.length - 1; i >= 0; i--) {
+ for (int j = nums.length - 1; j > i; j--) {
+ if (nums[j] > nums[i]) {
+ // 交换
+ int temp = nums[i];
+ nums[i] = nums[j];
+ nums[j] = temp;
+ // [i + 1, nums.length) 内元素升序排序
+ Arrays.sort(nums, i + 1, nums.length);
+ return;
+ }
+ }
+ }
+ Arrays.sort(nums); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
+ }
+}
```
## Python
@@ -120,5 +138,5 @@ public:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md
index 04f5eaf7..f83de1a8 100644
--- a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md
+++ b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md
@@ -14,7 +14,7 @@
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
-
+
示例 1:
* 输入:nums = [5,7,7,8,8,10], target = 8
@@ -50,21 +50,21 @@
接下来,在去寻找左边界,和右边界了。
-采用二分法来取寻找左右边界,为了让代码清晰,我分别写两个二分来寻找左边界和右边界。
+采用二分法来去寻找左右边界,为了让代码清晰,我分别写两个二分来寻找左边界和右边界。
**刚刚接触二分搜索的同学不建议上来就像如果用一个二分来查找左右边界,很容易把自己绕进去,建议扎扎实实的写两个二分分别找左边界和右边界**
## 寻找右边界
-先来寻找右边界,至于二分查找,如果看过[为什么每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)就会知道,二分查找中什么时候用while (left <= right),有什么时候用while (left < right),其实只要清楚**循环不变量**,很容易区分两种写法。
+先来寻找右边界,至于二分查找,如果看过[704.二分查找](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w)就会知道,二分查找中什么时候用while (left <= right),有什么时候用while (left < right),其实只要清楚**循环不变量**,很容易区分两种写法。
-那么这里我采用while (left <= right)的写法,区间定义为[left, right],即左闭又闭的区间(如果这里有点看不懂了,强烈建议把[为什么每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)这篇文章先看了,在把「leetcode:35.搜索插入位置」做了之后在做这道题目就好很多了)
+那么这里我采用while (left <= right)的写法,区间定义为[left, right],即左闭又闭的区间(如果这里有点看不懂了,强烈建议把[704.二分查找](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w)这篇文章先看了,704题目做了之后再做这道题目就好很多了)
确定好:计算出来的右边界是不包好target的右边界,左边界同理。
可以写出如下代码
-```C++
+```CPP
// 二分查找,寻找target的右边界(不包括target)
// 如果rightBorder为没有被赋值(即target在数组范围的左边,例如数组[3,3],target为2),为了处理情况一
int getRightBorder(vector& nums, int target) {
@@ -86,7 +86,7 @@ int getRightBorder(vector& nums, int target) {
## 寻找左边界
-```C++
+```CPP
// 二分查找,寻找target的左边界leftBorder(不包括target)
// 如果leftBorder没有被赋值(即target在数组范围的右边,例如数组[3,3],target为4),为了处理情况一
int getLeftBorder(vector& nums, int target) {
@@ -110,7 +110,7 @@ int getLeftBorder(vector& nums, int target) {
左右边界计算完之后,看一下主体代码,这里把上面讨论的三种情况,都覆盖了
-```C++
+```CPP
class Solution {
public:
vector searchRange(vector& nums, int target) {
@@ -173,11 +173,219 @@ private:
## Java
```java
+class Solution {
+ int[] searchRange(int[] nums, int target) {
+ int leftBorder = getLeftBorder(nums, target);
+ int rightBorder = getRightBorder(nums, target);
+ // 情况一
+ if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
+ // 情况三
+ if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
+ // 情况二
+ return new int[]{-1, -1};
+ }
+
+ int getRightBorder(int[] nums, int target) {
+ int left = 0;
+ int right = nums.length - 1;
+ int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
+ while (left <= right) {
+ int middle = left + ((right - left) / 2);
+ if (nums[middle] > target) {
+ right = middle - 1;
+ } else { // 寻找右边界,nums[middle] == target的时候更新left
+ left = middle + 1;
+ rightBorder = left;
+ }
+ }
+ return rightBorder;
+ }
+
+ int getLeftBorder(int[] nums, int target) {
+ int left = 0;
+ int right = nums.length - 1;
+ int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
+ while (left <= right) {
+ int middle = left + ((right - left) / 2);
+ if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
+ right = middle - 1;
+ leftBorder = right;
+ } else {
+ left = middle + 1;
+ }
+ }
+ return leftBorder;
+ }
+}
```
+```java
+// 解法2
+// 1、首先,在 nums 数组中二分查找 target;
+// 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
+// 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
+
+class Solution {
+ public int[] searchRange(int[] nums, int target) {
+ int index = binarySearch(nums, target); // 二分查找
+
+ if (index == -1) { // nums 中不存在 target,直接返回 {-1, -1}
+ return new int[] {-1, -1}; // 匿名数组
+ }
+ // nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
+ int left = index;
+ int right = index;
+ // 向左滑动,找左边界
+ while (left - 1 >= 0 && nums[left - 1] == nums[index]) { // 防止数组越界。逻辑短路,两个条件顺序不能换
+ left--;
+ }
+ // 向左滑动,找右边界
+ while (right + 1 < nums.length && nums[right + 1] == nums[index]) { // 防止数组越界。
+ right++;
+ }
+ return new int[] {left, right};
+ }
+
+ /**
+ * 二分查找
+ * @param nums
+ * @param target
+ */
+ public int binarySearch(int[] nums, int target) {
+ int left = 0;
+ int right = nums.length - 1; // 不变量:左闭右闭区间
+
+ while (left <= right) { // 不变量:左闭右闭区间
+ int mid = left + (right - left) / 2;
+ if (nums[mid] == target) {
+ return mid;
+ } else if (nums[mid] < target) {
+ left = mid + 1;
+ } else {
+ right = mid - 1; // 不变量:左闭右闭区间
+ }
+ }
+ return -1; // 不存在
+ }
+}
+```
+
+
+
## Python
```python
+class Solution:
+ def searchRange(self, nums: List[int], target: int) -> List[int]:
+ def getRightBorder(nums:List[int], target:int) -> int:
+ left, right = 0, len(nums)-1
+ rightBoder = -2 # 记录一下rightBorder没有被赋值的情况
+ while left <= right:
+ middle = left + (right-left) // 2
+ if nums[middle] > target:
+ right = middle - 1
+ else: # 寻找右边界,nums[middle] == target的时候更新left
+ left = middle + 1
+ rightBoder = left
+
+ return rightBoder
+
+ def getLeftBorder(nums:List[int], target:int) -> int:
+ left, right = 0, len(nums)-1
+ leftBoder = -2 # 记录一下leftBorder没有被赋值的情况
+ while left <= right:
+ middle = left + (right-left) // 2
+ if nums[middle] >= target: # 寻找左边界,nums[middle] == target的时候更新right
+ right = middle - 1;
+ leftBoder = right;
+ else:
+ left = middle + 1
+ return leftBoder
+ leftBoder = getLeftBorder(nums, target)
+ rightBoder = getRightBorder(nums, target)
+ # 情况一
+ if leftBoder == -2 or rightBoder == -2: return [-1, -1]
+ # 情况三
+ if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]
+ # 情况二
+ return [-1, -1]
+```
+```python
+# 解法2
+# 1、首先,在 nums 数组中二分查找 target;
+# 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
+# 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
+class Solution:
+ def searchRange(self, nums: List[int], target: int) -> List[int]:
+ def binarySearch(nums:List[int], target:int) -> int:
+ left, right = 0, len(nums)-1
+ while left<=right: # 不变量:左闭右闭区间
+ middle = left + (right-left) // 2
+ if nums[middle] > target:
+ right = middle - 1
+ elif nums[middle] < target:
+ left = middle + 1
+ else:
+ return middle
+ return -1
+ index = binarySearch(nums, target)
+ if index == -1:return [-1, -1] # nums 中不存在 target,直接返回 {-1, -1}
+ # nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
+ left, right = index, index
+ # 向左滑动,找左边界
+ while left -1 >=0 and nums[left - 1] == target: left -=1
+ # 向右滑动,找右边界
+ while right+1 < len(nums) and nums[right + 1] == target: right +=1
+ return [left, right]
+```
+```python
+# 解法3
+# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标(左边界)与第一个大于target的下标(右边界);
+# 2、如果左边界<= 右边界,则返回 [左边界, 右边界]。否则返回[-1, -1]
+class Solution:
+ def searchRange(self, nums: List[int], target: int) -> List[int]:
+ def binarySearch(nums:List[int], target:int, lower:bool) -> int:
+ left, right = 0, len(nums)-1
+ ans = len(nums)
+ while left<=right: # 不变量:左闭右闭区间
+ middle = left + (right-left) //2
+ # lower为True,执行前半部分,找到第一个大于等于 target的下标 ,否则找到第一个大于target的下标
+ if nums[middle] > target or (lower and nums[middle] >= target):
+ right = middle - 1
+ ans = middle
+ else:
+ left = middle + 1
+ return ans
+
+ leftBorder = binarySearch(nums, target, True) # 搜索左边界
+ rightBorder = binarySearch(nums, target, False) -1 # 搜索右边界
+ if leftBorder<= rightBorder and rightBorder< len(nums) and nums[leftBorder] == target and nums[rightBorder] == target:
+ return [leftBorder, rightBorder]
+ return [-1, -1]
+```
+
+```python
+# 解法4
+# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标leftBorder;
+# 2、在 nums 数组中二分查找得到第一个大于等于 target+1的下标, 减1则得到rightBorder;
+# 3、如果开始位置在数组的右边或者不存在target,则返回[-1, -1] 。否则返回[leftBorder, rightBorder]
+class Solution:
+ def searchRange(self, nums: List[int], target: int) -> List[int]:
+ def binarySearch(nums:List[int], target:int) -> int:
+ left, right = 0, len(nums)-1
+ while left<=right: # 不变量:左闭右闭区间
+ middle = left + (right-left) //2
+ if nums[middle] >= target:
+ right = middle - 1
+ else:
+ left = middle + 1
+ return left # 若存在target,则返回第一个等于target的值
+
+ leftBorder = binarySearch(nums, target) # 搜索左边界
+ rightBorder = binarySearch(nums, target+1) -1 # 搜索右边界
+ if leftBorder == len(nums) or nums[leftBorder]!= target: # 情况一和情况二
+ return [-1, -1]
+ return [leftBorder, rightBorder]
```
## Go
@@ -194,6 +402,5 @@ private:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
-
+
diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md
index 0f826412..061573e0 100644
--- a/problems/0035.搜索插入位置.md
+++ b/problems/0035.搜索插入位置.md
@@ -116,7 +116,7 @@ public:
**大家要仔细看注释,思考为什么要写while(left <= right), 为什么要写right = middle - 1**。
-```C++
+```CPP
class Solution {
public:
int searchInsert(vector& nums, int target) {
@@ -158,7 +158,7 @@ public:
**大家要仔细看注释,思考为什么要写while (left < right), 为什么要写right = middle**。
-```cpp
+```CPP
class Solution {
public:
int searchInsert(vector& nums, int target) {
@@ -234,8 +234,6 @@ class Solution {
```
-
-
Python:
```python3
class Solution:
@@ -254,9 +252,6 @@ class Solution:
return right + 1
```
-
-Go:
-
JavaScript:
```js
var searchInsert = function (nums, target) {
@@ -277,9 +272,45 @@ var searchInsert = function (nums, target) {
};
```
+Swift:
+
+```swift
+// 暴力法
+func searchInsert(_ nums: [Int], _ target: Int) -> Int {
+ for i in 0..= target {
+ return i
+ }
+ }
+ return nums.count
+}
+
+// 二分法
+func searchInsert(_ nums: [Int], _ target: Int) -> Int {
+ var left = 0
+ var right = nums.count - 1
+
+ while left <= right {
+ let middle = left + ((right - left) >> 1)
+
+ if nums[middle] > target {
+ right = middle - 1
+ }else if nums[middle] < target {
+ left = middle + 1
+ }else if nums[middle] == target {
+ return middle
+ }
+ }
+
+ return right + 1
+}
+```
+
+
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md
index e43708b8..64be7013 100644
--- a/problems/0037.解数独.md
+++ b/problems/0037.解数独.md
@@ -90,7 +90,7 @@ bool backtracking(vector>& board)
代码如下:(**详细看注释**)
-```C++
+```CPP
bool backtracking(vector>& board) {
for (int i = 0; i < board.size(); i++) { // 遍历行
for (int j = 0; j < board[0].size(); j++) { // 遍历列
@@ -125,7 +125,7 @@ bool backtracking(vector>& board) {
代码如下:
-```C++
+```CPP
bool isValid(int row, int col, char val, vector>& board) {
for (int i = 0; i < 9; i++) { // 判断行里是否重复
if (board[row][i] == val) {
@@ -154,7 +154,7 @@ bool isValid(int row, int col, char val, vector>& board) {
## C++代码
-```C++
+```CPP
class Solution {
private:
bool backtracking(vector>& board) {
@@ -437,4 +437,4 @@ var solveSudoku = function(board) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0039.组合总和.md b/problems/0039.组合总和.md
index ba8128b5..0c452e22 100644
--- a/problems/0039.组合总和.md
+++ b/problems/0039.组合总和.md
@@ -73,7 +73,7 @@ candidates 中的数字可以无限制重复被选取。
代码如下:
-```C++
+```CPP
vector> result;
vector path;
void backtracking(vector& candidates, int target, int sum, int startIndex)
@@ -89,7 +89,7 @@ void backtracking(vector& candidates, int target, int sum, int startIndex)
sum等于target的时候,需要收集结果,代码如下:
-```C++
+```CPP
if (sum > target) {
return;
}
@@ -107,7 +107,7 @@ if (sum == target) {
如何重复选取呢,看代码,注释部分:
-```C++
+```CPP
for (int i = startIndex; i < candidates.size(); i++) {
sum += candidates[i];
path.push_back(candidates[i]);
@@ -119,7 +119,7 @@ for (int i = startIndex; i < candidates.size(); i++) {
按照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中给出的模板,不难写出如下C++完整代码:
-```C++
+```CPP
// 版本一
class Solution {
private:
@@ -179,7 +179,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target;
整体代码如下:(注意注释的部分)
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -351,4 +351,4 @@ var combinationSum = function(candidates, target) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md
index 70e012da..5ea11ca7 100644
--- a/problems/0040.组合总和II.md
+++ b/problems/0040.组合总和II.md
@@ -90,7 +90,7 @@ candidates 中的每个数字在每个组合中只能使用一次。
代码如下:
-```C++
+```CPP
vector> result; // 存放组合集合
vector path; // 符合条件的组合
void backtracking(vector& candidates, int target, int sum, int startIndex, vector& used) {
@@ -102,7 +102,7 @@ void backtracking(vector& candidates, int target, int sum, int startIndex,
代码如下:
-```C++
+```CPP
if (sum > target) { // 这个条件其实可以省略
return;
}
@@ -137,7 +137,7 @@ if (sum == target) {
那么单层搜索的逻辑代码如下:
-```C++
+```CPP
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++) {
// used[i - 1] == true,说明同一树支candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
@@ -161,7 +161,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target;
回溯三部曲分析完了,整体C++代码如下:
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -206,7 +206,7 @@ public:
这里直接用startIndex来去重也是可以的, 就不用used数组了。
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -398,4 +398,4 @@ var combinationSum2 = function(candidates, target) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md
index 3f4d0123..a2cb2345 100644
--- a/problems/0042.接雨水.md
+++ b/problems/0042.接雨水.md
@@ -77,7 +77,7 @@
一样的方法,只要从头遍历一遍所有的列,然后求出每一列雨水的体积,相加之后就是总雨水的体积了。
首先从头遍历所有的列,并且**要注意第一个柱子和最后一个柱子不接雨水**,代码如下:
-```C++
+```CPP
for (int i = 0; i < height.size(); i++) {
// 第一个柱子和最后一个柱子不接雨水
if (i == 0 || i == height.size() - 1) continue;
@@ -86,7 +86,7 @@ for (int i = 0; i < height.size(); i++) {
在for循环中求左右两边最高柱子,代码如下:
-```C++
+```CPP
int rHeight = height[i]; // 记录右边柱子的最高高度
int lHeight = height[i]; // 记录左边柱子的最高高度
for (int r = i + 1; r < height.size(); r++) {
@@ -99,14 +99,14 @@ for (int l = i - 1; l >= 0; l--) {
最后,计算该列的雨水高度,代码如下:
-```C++
+```CPP
int h = min(lHeight, rHeight) - height[i];
if (h > 0) sum += h; // 注意只有h大于零的时候,在统计到总和中
```
整体代码如下:
-```C++
+```CPP
class Solution {
public:
int trap(vector& height) {
@@ -152,7 +152,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
int trap(vector& height) {
@@ -287,7 +287,7 @@ if (height[i] == height[st.top()]) { // 例如 5 5 1 7 这种情况
求当前凹槽雨水的体积代码如下:
-```C++
+```CPP
while (!st.empty() && height[i] > height[st.top()]) { // 注意这里是while,持续跟新栈顶元素
int mid = st.top();
st.pop();
@@ -301,7 +301,7 @@ while (!st.empty() && height[i] > height[st.top()]) { // 注意这里是while,
关键部分讲完了,整体代码如下:
-```C++
+```CPP
class Solution {
public:
int trap(vector& height) {
@@ -335,7 +335,7 @@ public:
以上代码冗余了一些,但是思路是清晰的,下面我将代码精简一下,如下:
-```C++
+```CPP
class Solution {
public:
int trap(vector& height) {
@@ -388,6 +388,44 @@ class Solution:
res += res1
return res
```
+动态规划
+```python3
+class Solution:
+ def trap(self, height: List[int]) -> int:
+ leftheight, rightheight = [0]*len(height), [0]*len(height)
+
+ leftheight[0]=height[0]
+ for i in range(1,len(height)):
+ leftheight[i]=max(leftheight[i-1],height[i])
+ rightheight[-1]=height[-1]
+ for i in range(len(height)-2,-1,-1):
+ rightheight[i]=max(rightheight[i+1],height[i])
+
+ result = 0
+ for i in range(0,len(height)):
+ summ = min(leftheight[i],rightheight[i])-height[i]
+ result += summ
+ return result
+```
+单调栈
+```python3
+class Solution:
+ def trap(self, height: List[int]) -> int:
+ st =[0]
+ result = 0
+ for i in range(1,len(height)):
+ while st!=[] and height[i]>height[st[-1]]:
+ midh = height[st[-1]]
+ st.pop()
+ if st!=[]:
+ hright = height[i]
+ hleft = height[st[-1]]
+ h = min(hright,hleft)-midh
+ w = i-st[-1]-1
+ result+=h*w
+ st.append(i)
+ return result
+```
Go:
@@ -398,4 +436,4 @@ JavaScript:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md
index a161d944..d946315b 100644
--- a/problems/0045.跳跃游戏II.md
+++ b/problems/0045.跳跃游戏II.md
@@ -63,7 +63,7 @@
C++代码如下:(详细注释)
-```C++
+```CPP
// 版本一
class Solution {
public:
@@ -106,7 +106,7 @@ public:
代码如下:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -236,4 +236,4 @@ var jump = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md
index 3ee7271e..c0626fb7 100644
--- a/problems/0046.全排列.md
+++ b/problems/0046.全排列.md
@@ -106,7 +106,7 @@ for (int i = 0; i < nums.size(); i++) {
整体C++代码如下:
-```C++
+```CPP
class Solution {
public:
vector> result;
@@ -227,24 +227,27 @@ class Solution:
Go:
```Go
-var result [][]int
-func backtrack(nums,pathNums []int,used []bool){
- if len(nums)==len(pathNums){
- tmp:=make([]int,len(nums))
- copy(tmp,pathNums)
- result=append(result,tmp)
- //result=append(result,pathNums)
- return
- }
- for i:=0;i
+
diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md
index 66107c95..61428299 100644
--- a/problems/0047.全排列II.md
+++ b/problems/0047.全排列II.md
@@ -228,35 +228,31 @@ Go:
```go
var res [][]int
func permute(nums []int) [][]int {
- res = [][]int{}
- sort.Ints(nums)
- dfs(nums, make([]int, 0), make([]bool, len(nums)))
- return res
+ res = [][]int{}
+ backTrack(nums,len(nums),[]int{})
+ return res
}
+func backTrack(nums []int,numsLen int,path []int) {
+ if len(nums)==0{
+ p:=make([]int,len(path))
+ copy(p,path)
+ res = append(res,p)
+ }
+ used := [21]int{}//跟前一题唯一的区别,同一层不使用重复的数。关于used的思想carl在递增子序列那一题中提到过
+ for i:=0;i
+
diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md
index a8919ec3..387e75c3 100644
--- a/problems/0051.N皇后.md
+++ b/problems/0051.N皇后.md
@@ -171,7 +171,7 @@ bool isValid(int row, int col, vector& chessboard, int n) {
## C++代码
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -490,4 +490,4 @@ var solveNQueens = function(n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md
index 81e0b35a..cba7d6c7 100644
--- a/problems/0053.最大子序和.md
+++ b/problems/0053.最大子序和.md
@@ -25,7 +25,7 @@
时间复杂度:O(n^2)
空间复杂度:O(1)
-```C++
+```CPP
class Solution {
public:
int maxSubArray(vector& nums) {
@@ -81,7 +81,7 @@ if (count > result) result = count;
那么不难写出如下C++代码(关键地方已经注释)
-```C++
+```CPP
class Solution {
public:
int maxSubArray(vector& nums) {
@@ -109,7 +109,7 @@ public:
那么先给出我的dp代码如下,有时间的录友可以提前做一做:
-```C++
+```CPP
class Solution {
public:
int maxSubArray(vector& nums) {
@@ -214,4 +214,4 @@ var maxSubArray = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0053.最大子序和(动态规划).md b/problems/0053.最大子序和(动态规划).md
index dd0e513b..0932c77f 100644
--- a/problems/0053.最大子序和(动态规划).md
+++ b/problems/0053.最大子序和(动态规划).md
@@ -65,7 +65,7 @@ dp[0]应该是多少呢?
以上动规五部曲分析完毕,完整代码如下:
-```C++
+```CPP
class Solution {
public:
int maxSubArray(vector& nums) {
@@ -138,7 +138,52 @@ class Solution:
```
Go:
+```Go
+// solution
+// 1, dp
+// 2, 贪心
+func maxSubArray(nums []int) int {
+ n := len(nums)
+ // 这里的dp[i] 表示,最大的连续子数组和,包含num[i] 元素
+ dp := make([]int,n)
+ // 初始化,由于dp 状态转移方程依赖dp[0]
+ dp[0] = nums[0]
+ // 初始化最大的和
+ mx := nums[0]
+ for i:=1;ib {
+ return a
+ }
+ return b
+}
+```
+
+JavaScript:
+
+```javascript
+const maxSubArray = nums => {
+ // 数组长度,dp初始化
+ const [len, dp] = [nums.length, [nums[0]]];
+ // 最大值初始化为dp[0]
+ let max = dp[0];
+ for (let i = 1; i < len; i++) {
+ dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
+ // 更新最大值
+ max = Math.max(max, dp[i]);
+ }
+ return max;
+};
+```
@@ -146,4 +191,4 @@ Go:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md
index 8618515e..0b1c1d36 100644
--- a/problems/0055.跳跃游戏.md
+++ b/problems/0055.跳跃游戏.md
@@ -58,7 +58,7 @@ i每次移动只能在cover的范围内移动,每移动一个元素,cover得
C++代码如下:
-```C++
+```CPP
class Solution {
public:
bool canJump(vector& nums) {
@@ -161,4 +161,4 @@ var canJump = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0056.合并区间.md b/problems/0056.合并区间.md
index d4ffc554..441cc63c 100644
--- a/problems/0056.合并区间.md
+++ b/problems/0056.合并区间.md
@@ -56,7 +56,7 @@
C++代码如下:
-```C++
+```CPP
class Solution {
public:
// 按照区间左边界从小到大排序
@@ -92,7 +92,7 @@ public:
当然以上代码有冗余一些,可以优化一下,如下:(思路是一样的)
-```C++
+```CPP
class Solution {
public:
vector> merge(vector>& intervals) {
@@ -176,30 +176,27 @@ class Solution:
```
Go:
-```Go
+```golang
func merge(intervals [][]int) [][]int {
- sort.Slice(intervals, func(i, j int) bool {
- return intervals[i][0]=intervals[i+1][0]{
+ intervals[i][1]=max(intervals[i][1],intervals[i+1][1])//赋值最大值
+ intervals=append(intervals[:i+1],intervals[i+2:]...)
+ i--
+ }
+ }
+ return intervals
}
-func max(a, b int) int {
- if a > b { return a }
- return b
+func max(a,b int)int{
+ if a>b{
+ return a
+ }
+ return b
}
```
@@ -229,4 +226,4 @@ var merge = function (intervals) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md
index 90b74005..6df8c83d 100644
--- a/problems/0059.螺旋矩阵II.md
+++ b/problems/0059.螺旋矩阵II.md
@@ -66,7 +66,7 @@
整体C++代码如下:
-```C++
+```CPP
class Solution {
public:
vector> generateMatrix(int n) {
@@ -302,6 +302,61 @@ func generateMatrix(n int) [][]int {
}
```
+Swift:
+
+```swift
+func generateMatrix(_ n: Int) -> [[Int]] {
+ var result = [[Int]](repeating: [Int](repeating: 0, count: n), count: n)
+
+ var startRow = 0
+ var startColumn = 0
+ var loopCount = n / 2
+ let mid = n / 2
+ var count = 1
+ var offset = 1
+ var row: Int
+ var column: Int
+
+ while loopCount > 0 {
+ row = startRow
+ column = startColumn
+
+ for c in column ..< startColumn + n - offset {
+ result[startRow][c] = count
+ count += 1
+ column += 1
+ }
+
+ for r in row ..< startRow + n - offset {
+ result[r][column] = count
+ count += 1
+ row += 1
+ }
+
+ for _ in startColumn ..< column {
+ result[row][column] = count
+ count += 1
+ column -= 1
+ }
+
+ for _ in startRow ..< row {
+ result[row][column] = count
+ count += 1
+ row -= 1
+ }
+
+ startRow += 1
+ startColumn += 1
+ offset += 2
+ loopCount -= 1
+ }
+
+ if (n % 2) != 0 {
+ result[mid][mid] = count
+ }
+ return result
+}
+```
@@ -309,4 +364,4 @@ func generateMatrix(n int) [][]int {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md
index 50e70b3e..84c84075 100644
--- a/problems/0062.不同路径.md
+++ b/problems/0062.不同路径.md
@@ -59,7 +59,7 @@
此时问题就可以转化为求二叉树叶子节点的个数,代码如下:
-```C++
+```CPP
class Solution {
private:
int dfs(int i, int j, int m, int n) {
@@ -128,7 +128,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
以上动规五部曲分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int uniquePaths(int m, int n) {
@@ -149,7 +149,7 @@ public:
其实用一个一维数组(也可以理解是滚动数组)就可以了,但是不利于理解,可以优化点空间,建议先理解了二维,在理解一维,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int uniquePaths(int m, int n) {
@@ -187,7 +187,7 @@ public:
例如如下代码是不行的。
-```C++
+```CPP
class Solution {
public:
int uniquePaths(int m, int n) {
@@ -204,7 +204,7 @@ public:
需要在计算分子的时候,不断除以分母,代码如下:
-```C++
+```CPP
class Solution {
public:
int uniquePaths(int m, int n) {
@@ -333,4 +333,4 @@ var uniquePaths = function(m, n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md
index a61ffd02..3df1b301 100644
--- a/problems/0063.不同路径II.md
+++ b/problems/0063.不同路径II.md
@@ -97,7 +97,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
所以本题初始化代码为:
-```C++
+```CPP
vector> dp(m, vector(n, 0));
for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++) dp[i][0] = 1;
for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
@@ -111,7 +111,7 @@ for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
代码如下:
-```C++
+```CPP
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1) continue;
@@ -135,7 +135,7 @@ for (int i = 1; i < m; i++) {
动规五部分分析完毕,对应C++代码如下:
-```C++
+```CPP
class Solution {
public:
int uniquePathsWithObstacles(vector>& obstacleGrid) {
@@ -341,4 +341,4 @@ var uniquePathsWithObstacles = function(obstacleGrid) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md
index 96899d37..bb9a757c 100644
--- a/problems/0070.爬楼梯.md
+++ b/problems/0070.爬楼梯.md
@@ -109,7 +109,7 @@ dp[i]: 爬到第i层楼梯,有dp[i]种方法
以上五部分析完之后,C++代码如下:
-```C++
+```CPP
// 版本一
class Solution {
public:
@@ -130,7 +130,7 @@ public:
当然依然也可以,优化一下空间复杂度,代码如下:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -163,7 +163,7 @@ public:
这里我先给出我的实现代码:
-```C++
+```CPP
class Solution {
public:
int climbStairs(int n) {
@@ -301,4 +301,4 @@ var climbStairs = function(n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0070.爬楼梯完全背包版本.md b/problems/0070.爬楼梯完全背包版本.md
index b3e7eb73..f7a80f3b 100644
--- a/problems/0070.爬楼梯完全背包版本.md
+++ b/problems/0070.爬楼梯完全背包版本.md
@@ -193,4 +193,4 @@ func climbStairs(n int) int {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md
index 9ddca7c0..8ec0a65b 100644
--- a/problems/0072.编辑距离.md
+++ b/problems/0072.编辑距离.md
@@ -91,18 +91,18 @@ if (word1[i - 1] != word2[j - 1])
`if (word1[i - 1] != word2[j - 1])`,此时就需要编辑了,如何编辑呢?
-操作一:word1增加一个元素,使其word1[i - 1]与word2[j - 1]相同,那么就是以下标i-2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 加上一个增加元素的操作。
+* 操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。
即 `dp[i][j] = dp[i - 1][j] + 1;`
-操作二:word2添加一个元素,使其word1[i - 1]与word2[j - 1]相同,那么就是以下标i-1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 加上一个增加元素的操作。
+* 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。
即 `dp[i][j] = dp[i][j - 1] + 1;`
-这里有同学发现了,怎么都是添加元素,删除元素去哪了。
+这里有同学发现了,怎么都是删除元素,添加元素去哪了。
-**word2添加一个元素,相当于word1删除一个元素**,例如 `word1 = "ad" ,word2 = "a"`,`word1`删除元素`'d'`,`word2`添加一个元素`'d'`,变成`word1="a", word2="ad"`, 最终的操作数是一样! dp数组如下图所示意的:
+**word2添加一个元素,相当于word1删除一个元素**,例如 `word1 = "ad" ,word2 = "a"`,`word1`删除元素`'d'` 和 `word2`添加一个元素`'d'`,变成`word1="a", word2="ad"`, 最终的操作数是一样! dp数组如下图所示意的:
```
a a d
@@ -123,7 +123,7 @@ if (word1[i - 1] != word2[j - 1])
递归公式代码如下:
-```C++
+```CPP
if (word1[i - 1] == word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
@@ -151,7 +151,7 @@ dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最
所以C++代码如下:
-```C++
+```CPP
for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
```
@@ -175,7 +175,7 @@ for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
代码如下:
-```C++
+```CPP
for (int i = 1; i <= word1.size(); i++) {
for (int j = 1; j <= word2.size(); j++) {
if (word1[i - 1] == word2[j - 1]) {
@@ -198,7 +198,7 @@ for (int i = 1; i <= word1.size(); i++) {
以上动规五部分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int minDistance(string word1, string word2) {
@@ -338,4 +338,4 @@ const minDistance = (word1, word2) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0077.组合.md b/problems/0077.组合.md
index 0b289a40..d88a5711 100644
--- a/problems/0077.组合.md
+++ b/problems/0077.组合.md
@@ -173,7 +173,7 @@ for循环每次从startIndex开始遍历,然后用path保存取到的节点i
代码如下:
-```C++
+```CPP
for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始
@@ -188,7 +188,7 @@ backtracking的下面部分就是回溯的操作了,撤销本次处理的结
关键地方都讲完了,组合问题C++完整代码如下:
-```C++
+```CPP
class Solution {
private:
vector> result; // 存放符合条件结果的集合
@@ -440,4 +440,4 @@ func backtrack(n,k,start int,track []int){
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0077.组合优化.md b/problems/0077.组合优化.md
index d3e82f09..d545543d 100644
--- a/problems/0077.组合优化.md
+++ b/problems/0077.组合优化.md
@@ -249,4 +249,4 @@ var combine = function(n, k) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0078.子集.md b/problems/0078.子集.md
index 0b2f3c09..ca49f97b 100644
--- a/problems/0078.子集.md
+++ b/problems/0078.子集.md
@@ -120,7 +120,7 @@ void backtracking(参数) {
可以写出如下回溯算法C++代码:
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -268,4 +268,4 @@ var subsets = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0084.柱状图中最大的矩形.md b/problems/0084.柱状图中最大的矩形.md
new file mode 100644
index 00000000..941888db
--- /dev/null
+++ b/problems/0084.柱状图中最大的矩形.md
@@ -0,0 +1,247 @@
+
+
+# 84.柱状图中最大的矩形
+
+链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
+
+给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
+
+求在该柱状图中,能够勾勒出来的矩形的最大面积。
+
+
+
+
+
+
+# 思路
+
+本题和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
+
+其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)
+
+我们先来看一下双指针的解法:
+
+## 双指针解法
+
+```CPP
+class Solution {
+public:
+ int largestRectangleArea(vector& heights) {
+ int sum = 0;
+ for (int i = 0; i < heights.size(); i++) {
+ int left = i;
+ int right = i;
+ for (; left >= 0; left--) {
+ if (heights[left] < heights[i]) break;
+ }
+ for (; right < heights.size(); right++) {
+ if (heights[right] < heights[i]) break;
+ }
+ int w = right - left - 1;
+ int h = heights[i];
+ sum = max(sum, w * h);
+ }
+ return sum;
+ }
+};
+```
+
+如上代码并不能通过leetcode,超时了,因为时间复杂度是O(n^2)。
+
+## 动态规划
+
+本题动态规划的写法整体思路和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是一致的,但要比[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)难一些。
+
+难就难在本题要记录记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。
+
+所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中已经介绍了。
+
+```CPP
+class Solution {
+public:
+ int largestRectangleArea(vector& heights) {
+ vector minLeftIndex(heights.size());
+ vector minRightIndex(heights.size());
+ int size = heights.size();
+
+ // 记录每个柱子 左边第一个小于该柱子的下标
+ minLeftIndex[0] = -1; // 注意这里初始化,防止下面while死循环
+ for (int i = 1; i < size; i++) {
+ int t = i - 1;
+ // 这里不是用if,而是不断向左寻找的过程
+ while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
+ minLeftIndex[i] = t;
+ }
+ // 记录每个柱子 右边第一个小于该柱子的下标
+ minRightIndex[size - 1] = size; // 注意这里初始化,防止下面while死循环
+ for (int i = size - 2; i >= 0; i--) {
+ int t = i + 1;
+ // 这里不是用if,而是不断向右寻找的过程
+ while (t < size && heights[t] >= heights[i]) t = minRightIndex[t];
+ minRightIndex[i] = t;
+ }
+ // 求和
+ int result = 0;
+ for (int i = 0; i < size; i++) {
+ int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
+ result = max(sum, result);
+ }
+ return result;
+ }
+};
+```
+
+## 单调栈
+
+本地单调栈的解法和接雨水的题目是遥相呼应的。
+
+为什么这么说呢,[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
+
+**这里就涉及到了单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小**。
+
+在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
+
+那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!
+
+我来举一个例子,如图:
+
+
+
+只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。
+
+所以本题单调栈的顺序正好与接雨水反过来。
+
+此时大家应该可以发现其实就是**栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度**
+
+理解这一点,对单调栈就掌握的比较到位了。
+
+除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
+
+剩下就是分析清楚如下三种情况:
+
+* 情况一:当前遍历的元素heights[i]小于栈顶元素heights[st.top()]的情况
+* 情况二:当前遍历的元素heights[i]等于栈顶元素heights[st.top()]的情况
+* 情况三:当前遍历的元素heights[i]大于栈顶元素heights[st.top()]的情况
+
+C++代码如下:
+
+```CPP
+// 版本一
+class Solution {
+public:
+ int largestRectangleArea(vector& heights) {
+ stack st;
+ heights.insert(heights.begin(), 0); // 数组头部加入元素0
+ heights.push_back(0); // 数组尾部加入元素0
+ st.push(0);
+ int result = 0;
+ // 第一个元素已经入栈,从下表1开始
+ for (int i = 1; i < heights.size(); i++) {
+ // 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下表
+ if (heights[i] > heights[st.top()]) {
+ st.push(i);
+ } else if (heights[i] == heights[st.top()]) {
+ st.pop(); // 这个可以加,可以不加,效果一样,思路不同
+ st.push(i);
+ } else {
+ while (heights[i] < heights[st.top()]) { // 注意是while
+ int mid = st.top();
+ st.pop();
+ int left = st.top();
+ int right = i;
+ int w = right - left - 1;
+ int h = heights[mid];
+ result = max(result, w * h);
+ }
+ st.push(i);
+ }
+ }
+ return result;
+ }
+};
+
+```
+
+代码精简之后:
+
+```CPP
+// 版本二
+class Solution {
+public:
+ int largestRectangleArea(vector& heights) {
+ stack st;
+ heights.insert(heights.begin(), 0); // 数组头部加入元素0
+ heights.push_back(0); // 数组尾部加入元素0
+ st.push(0);
+ int result = 0;
+ for (int i = 1; i < heights.size(); i++) {
+ while (heights[i] < heights[st.top()]) {
+ int mid = st.top();
+ st.pop();
+ int w = i - st.top() - 1;
+ int h = heights[mid];
+ result = max(result, w * h);
+ }
+ st.push(i);
+ }
+ return result;
+ }
+};
+```
+
+这里我依然建议大家按部就班把版本一写出来,把情况一二三分析清楚,然后在精简代码到版本二。 直接看版本二容易忽略细节!
+
+## 其他语言版本
+
+Java:
+
+Python:
+
+动态规划
+```python3
+class Solution:
+ def largestRectangleArea(self, heights: List[int]) -> int:
+ result = 0
+ minleftindex, minrightindex = [0]*len(heights), [0]*len(heights)
+
+ minleftindex[0]=-1
+ for i in range(1,len(heights)):
+ t = i-1
+ while t>=0 and heights[t]>=heights[i]: t=minleftindex[t]
+ minleftindex[i]=t
+
+ minrightindex[-1]=len(heights)
+ for i in range(len(heights)-2,-1,-1):
+ t=i+1
+ while t=heights[i]: t=minrightindex[t]
+ minrightindex[i]=t
+
+ for i in range(0,len(heights)):
+ left = minleftindex[i]
+ right = minrightindex[i]
+ summ = (right-left-1)*heights[i]
+ result = max(result,summ)
+ return result
+```
+单调栈 版本二
+```python3
+class Solution:
+ def largestRectangleArea(self, heights: List[int]) -> int:
+ heights.insert(0,0) # 数组头部加入元素0
+ heights.append(0) # 数组尾部加入元素0
+ st = [0]
+ result = 0
+ for i in range(1,len(heights)):
+ while st!=[] and heights[i]
diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md
index 71aef5c7..5c19adc0 100644
--- a/problems/0090.子集II.md
+++ b/problems/0090.子集II.md
@@ -124,7 +124,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -288,4 +288,4 @@ var subsetsWithDup = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md
index 40ad7684..9a95af22 100644
--- a/problems/0093.复原IP地址.md
+++ b/problems/0093.复原IP地址.md
@@ -183,7 +183,7 @@ void backtracking(参数) {
可以写出如下回溯算法C++代码:
-```C++
+```CPP
class Solution {
private:
vector result;// 记录结果
@@ -453,4 +453,4 @@ func isNormalIp(s string,startIndex,end int)bool{
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md
index 56f50d46..7cbe4fec 100644
--- a/problems/0096.不同的二叉搜索树.md
+++ b/problems/0096.不同的二叉搜索树.md
@@ -103,7 +103,7 @@ j相当于是头结点的元素,从1遍历到i为止。
代码如下:
-```C++
+```CPP
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
@@ -123,7 +123,7 @@ n为5时候的dp数组状态如图:
综上分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int numTrees(int n) {
@@ -234,4 +234,4 @@ const numTrees =(n) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md
index 248d10f1..6f7e5c14 100644
--- a/problems/0098.验证二叉搜索树.md
+++ b/problems/0098.验证二叉搜索树.md
@@ -32,7 +32,7 @@
可以递归中序遍历将二叉搜索树转变成一个数组,代码如下:
-```C++
+```CPP
vector vec;
void traversal(TreeNode* root) {
if (root == NULL) return;
@@ -44,7 +44,7 @@ void traversal(TreeNode* root) {
然后只要比较一下,这个数组是否是有序的,**注意二叉搜索树中不能有重复元素**。
-```C++
+```CPP
traversal(root);
for (int i = 1; i < vec.size(); i++) {
// 注意要小于等于,搜索树里不能有相同元素
@@ -55,7 +55,7 @@ return true;
整体代码如下:
-```C++
+```CPP
class Solution {
private:
vector vec;
@@ -103,7 +103,7 @@ if (root->val > root->left->val && root->val < root->right->val) {

-节点10小于左节点5,大于右节点15,但右子树里出现了一个6 这就不符合了!
+节点10大于左节点5,小于右节点15,但右子树里出现了一个6 这就不符合了!
* 陷阱2
@@ -163,7 +163,7 @@ return left && right;
整体代码如下:
-```C++
+```CPP
class Solution {
public:
long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
@@ -189,7 +189,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* pre = NULL; // 用来记录前一个节点
@@ -214,7 +214,7 @@ public:
迭代法中序遍历稍加改动就可以了,代码如下:
-```C++
+```CPP
class Solution {
public:
bool isValidBST(TreeNode* root) {
@@ -337,6 +337,8 @@ class Solution {
```
Python:
+
+**递归** - 利用BST中序遍历特性,把树"压缩"成数组
```python
# Definition for a binary tree node.
# class TreeNode:
@@ -344,29 +346,56 @@ Python:
# self.val = val
# self.left = left
# self.right = right
-# 递归法
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
- res = [] //把二叉搜索树按中序遍历写成list
- def buildalist(root):
- if not root: return
- buildalist(root.left) //左
- res.append(root.val) //中
- buildalist(root.right) //右
- return res
- buildalist(root)
- return res == sorted(res) and len(set(res)) == len(res) //检查list里的数有没有重复元素,以及是否按从小到大排列
+ # 思路: 利用BST中序遍历的特性.
+ # 中序遍历输出的二叉搜索树节点的数值是有序序列
+ candidate_list = []
+
+ def __traverse(root: TreeNode) -> None:
+ nonlocal candidate_list
+ if not root:
+ return
+ __traverse(root.left)
+ candidate_list.append(root.val)
+ __traverse(root.right)
+
+ def __is_sorted(nums: list) -> bool:
+ for i in range(1, len(nums)):
+ if nums[i] <= nums[i - 1]: # ⚠️ 注意: Leetcode定义二叉搜索树中不能有重复元素
+ return False
+ return True
+
+ __traverse(root)
+ res = __is_sorted(candidate_list)
+
+ return res
+```
-# 简单递归法
+**递归** - 标准做法
+
+```python
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
- def isBST(root, min_val, max_val):
- if not root: return True
- if root.val >= max_val or root.val <= min_val:
+ # 规律: BST的中序遍历节点数值是从小到大.
+ cur_max = -float("INF")
+ def __isValidBST(root: TreeNode) -> bool:
+ nonlocal cur_max
+
+ if not root:
+ return True
+
+ is_left_valid = __isValidBST(root.left)
+ if cur_max < root.val:
+ cur_max = root.val
+ else:
return False
- return isBST(root.left, min_val, root.val) and isBST(root.right, root.val, max_val)
- return isBST(root, float("-inf"), float("inf"))
-
+ is_right_valid = __isValidBST(root.right)
+
+ return is_left_valid and is_right_valid
+ return __isValidBST(root)
+```
+```
# 迭代-中序遍历
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
@@ -504,4 +533,4 @@ var isValidBST = function (root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0100.相同的树.md b/problems/0100.相同的树.md
index b536ffe3..df0a5dd1 100644
--- a/problems/0100.相同的树.md
+++ b/problems/0100.相同的树.md
@@ -61,7 +61,7 @@ bool compare(TreeNode* tree1, TreeNode* tree2)
此时tree1、tree2节点不为空,且数值也不相同的情况我们也处理了。
代码如下:
-```C++
+```CPP
if (tree1 == NULL && tree2 != NULL) return false;
else if (tree1 != NULL && tree2 == NULL) return false;
else if (tree1 == NULL && tree2 == NULL) return true;
@@ -77,7 +77,7 @@ else if (tree1->val != tree2->val) return false; // 注意这里我没有
代码如下:
-```C++
+```CPP
bool left = compare(tree1->left, tree2->left); // 左子树:左、 右子树:左
bool right = compare(tree1->right, tree2->right); // 左子树:右、 右子树:右
bool isSame = left && right; // 左子树:中、 右子树:中(逻辑处理)
@@ -85,7 +85,7 @@ return isSame;
```
最后递归的C++整体代码如下:
-```C++
+```CPP
class Solution {
public:
bool compare(TreeNode* tree1, TreeNode* tree2) {
@@ -119,7 +119,7 @@ public:
## 递归
-```C++
+```CPP
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
@@ -138,30 +138,30 @@ public:
## 迭代法
-```C++
-lass Solution {
+```CPP
+class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p == NULL && q == NULL) return true;
if (p == NULL || q == NULL) return false;
queue que;
- que.push(p); //
- que.push(q); //
+ que.push(p); // 添加根节点p
+ que.push(q); // 添加根节点q
while (!que.empty()) { //
TreeNode* leftNode = que.front(); que.pop();
TreeNode* rightNode = que.front(); que.pop();
- if (!leftNode && !rightNode) { //
+ if (!leftNode && !rightNode) { // 若p的节点与q的节点都为空
continue;
}
- //
+ // 若p的节点与q的节点有一个为空或p的节点的值与q节点不同
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
return false;
}
- que.push(leftNode->left); //
- que.push(rightNode->left); //
- que.push(leftNode->right); //
- que.push(rightNode->right); //
+ que.push(leftNode->left); // 添加p节点的左子树节点
+ que.push(rightNode->left); // 添加q节点的左子树节点
+ que.push(leftNode->right); // 添加p节点的右子树节点
+ que.push(rightNode->right); // 添加q节点的右子树节点
}
return true;
}
@@ -172,8 +172,72 @@ public:
Java:
-Python:
+```java
+// 递归法
+class Solution {
+ public boolean isSameTree(TreeNode p, TreeNode q) {
+ if (p == null && q == null) return true;
+ else if (q == null || p == null) return false;
+ else if (q.val != p.val) return false;
+ return isSameTree(q.left, p.left) && isSameTree(q.right, p.right);
+ }
+}
+```
+```java
+// 迭代法
+class Solution {
+ public boolean isSameTree(TreeNode p, TreeNode q) {
+ if(p == null && q == null) return true;
+ if(p == null || q == null) return false;
+ Queue que= new LinkedList();
+ que.offer(p);
+ que.offer(q);
+ while(!que.isEmpty()){
+ TreeNode leftNode = que.poll();
+ TreeNode rightNode = que.poll();
+ if(leftNode == null && rightNode == null) continue;
+ if(leftNode == null || rightNode== null || leftNode.val != rightNode.val) return false;
+ que.offer(leftNode.left);
+ que.offer(rightNode.left);
+ que.offer(leftNode.right);
+ que.offer(rightNode.right);
+ }
+ return true;
+ }
+}
+```
+Python:
+```python
+# 递归法
+class Solution:
+ def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
+ if not p and not q: return True
+ elif not p or not q: return False
+ elif p.val != q.val: return False
+ return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
+```
+
+```python
+# 迭代法
+class Solution:
+ def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
+ if not p and not q: return True
+ if not p or not q: return False
+ que = collections.deque()
+ que.append(p)
+ que.append(q)
+ while que:
+ leftNode = que.popleft()
+ rightNode = que.popleft()
+ if not leftNode and not rightNode: continue
+ if not leftNode or not rightNode or leftNode.val != rightNode.val: return False
+ que.append(leftNode.left)
+ que.append(rightNode.left)
+ que.append(leftNode.right)
+ que.append(rightNode.right)
+ return True
+```
Go:
JavaScript:
@@ -182,5 +246,5 @@ JavaScript:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md
index 241564e9..e091844b 100644
--- a/problems/0101.对称二叉树.md
+++ b/problems/0101.对称二叉树.md
@@ -73,7 +73,7 @@ bool compare(TreeNode* left, TreeNode* right)
此时左右节点不为空,且数值也不相同的情况我们也处理了。
代码如下:
-```C++
+```CPP
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
@@ -93,7 +93,7 @@ else if (left->val != right->val) return false; // 注意这里我没有
代码如下:
-```C++
+```CPP
bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中(逻辑处理)
@@ -104,7 +104,7 @@ return isSame;
最后递归的C++整体代码如下:
-```C++
+```CPP
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
@@ -137,7 +137,7 @@ public:
**盲目的照着抄,结果就是:发现这是一道“简单题”,稀里糊涂的就过了,但是真正的每一步判断逻辑未必想到清楚。**
当然我可以把如上代码整理如下:
-```C++
+```CPP
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
@@ -177,7 +177,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
bool isSymmetric(TreeNode* root) {
@@ -212,7 +212,7 @@ public:
只要把队列原封不动的改成栈就可以了,我下面也给出了代码。
-```C++
+```CPP
class Solution {
public:
bool isSymmetric(TreeNode* root) {
@@ -251,6 +251,8 @@ public:
# 相关题目推荐
+这两道题目基本和本题是一样的,只要稍加修改就可以AC。
+
* 100.相同的树
* 572.另一个树的子树
@@ -579,4 +581,4 @@ var isSymmetric = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md
index 8be3ac47..0f9b2df6 100644
--- a/problems/0102.二叉树的层序遍历.md
+++ b/problems/0102.二叉树的层序遍历.md
@@ -6,11 +6,8 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-# 二叉树的层序遍历
-看完这篇文章虽然不能打十个,但是可以迅速打八个!而且够快!
-
-学会二叉树的层序遍历,可以一口气撸完leetcode上八道题目:
+学会二叉树的层序遍历,可以一口气打完以下十题:
* 102.二叉树的层序遍历
* 107.二叉树的层次遍历II
@@ -20,9 +17,16 @@
* 515.在每个树行中找最大值
* 116.填充每个节点的下一个右侧节点指针
* 117.填充每个节点的下一个右侧节点指针II
+* 104.二叉树的最大深度
+* 111.二叉树的最小深度
+
+在之前写过这篇文章 [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog),可惜当时只打了5个,还不够,再给我一次机会,我打十个!
+
+
-## 102.二叉树的层序遍历
+
+# 102.二叉树的层序遍历
题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
@@ -38,7 +42,6 @@
* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)
* [二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)
-
接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。
@@ -53,11 +56,11 @@
这样就实现了层序从左到右遍历二叉树。
-代码如下:**这份代码也可以作为二叉树层序遍历的模板,以后再打七个就靠它了**。
+代码如下:**这份代码也可以作为二叉树层序遍历的模板,打十个就靠它了**。
C++代码:
-```
+```CPP
class Solution {
public:
vector> levelOrder(TreeNode* root) {
@@ -225,9 +228,10 @@ var levelOrder = function(root) {
```
-**此时我们就掌握了二叉树的层序遍历了,那么如下五道leetcode上的题目,只需要修改模板的一两行代码(不能再多了),便可打倒!**
+**此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!**
-## 107.二叉树的层次遍历 II
+
+# 107.二叉树的层次遍历 II
题目链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/
@@ -241,7 +245,7 @@ var levelOrder = function(root) {
C++代码:
-```C++
+```CPP
class Solution {
public:
vector> levelOrderBottom(TreeNode* root) {
@@ -404,7 +408,7 @@ var levelOrderBottom = function(root) {
```
-## 199.二叉树的右视图
+# 199.二叉树的右视图
题目链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/
@@ -418,7 +422,7 @@ var levelOrderBottom = function(root) {
C++代码:
-```C++
+```CPP
class Solution {
public:
vector rightSideView(TreeNode* root) {
@@ -581,7 +585,7 @@ var rightSideView = function(root) {
};
```
-## 637.二叉树的层平均值
+# 637.二叉树的层平均值
题目链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/
@@ -595,7 +599,7 @@ var rightSideView = function(root) {
C++代码:
-```C++
+```CPP
class Solution {
public:
vector averageOfLevels(TreeNode* root) {
@@ -765,7 +769,7 @@ var averageOfLevels = function(root) {
};
```
-## 429.N叉树的层序遍历
+# 429.N叉树的层序遍历
题目链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
@@ -790,7 +794,7 @@ var averageOfLevels = function(root) {
C++代码:
-```C++
+```CPP
class Solution {
public:
vector> levelOrder(Node* root) {
@@ -985,7 +989,7 @@ var levelOrder = function(root) {
};
```
-## 515.在每个树行中找最大值
+# 515.在每个树行中找最大值
题目链接:https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
@@ -999,7 +1003,7 @@ var levelOrder = function(root) {
C++代码:
-```C++
+```CPP
class Solution {
public:
vector largestValues(TreeNode* root) {
@@ -1042,6 +1046,31 @@ class Solution:
out_list.append(max(in_list))
return out_list
```
+java代码:
+
+```java
+class Solution {
+ public List largestValues(TreeNode root) {
+ List retVal = new ArrayList();
+ Queue tmpQueue = new LinkedList();
+ if (root != null) tmpQueue.add(root);
+
+ while (tmpQueue.size() != 0){
+ int size = tmpQueue.size();
+ List lvlVals = new ArrayList();
+ for (int index = 0; index < size; index++){
+ TreeNode node = tmpQueue.poll();
+ lvlVals.add(node.val);
+ if (node.left != null) tmpQueue.add(node.left);
+ if (node.right != null) tmpQueue.add(node.right);
+ }
+ retVal.add(Collections.max(lvlVals));
+ }
+
+ return retVal;
+ }
+}
+```
go:
@@ -1115,7 +1144,7 @@ var largestValues = function(root) {
};
```
-## 116.填充每个节点的下一个右侧节点指针
+# 116.填充每个节点的下一个右侧节点指针
题目链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
@@ -1143,7 +1172,7 @@ struct Node {
C++代码:
-```C++
+```CPP
class Solution {
public:
Node* connect(Node* root) {
@@ -1176,6 +1205,35 @@ public:
};
```
+java代码:
+
+```java
+class Solution {
+ public Node connect(Node root) {
+ Queue tmpQueue = new LinkedList();
+ if (root != null) tmpQueue.add(root);
+
+ while (tmpQueue.size() != 0){
+ int size = tmpQueue.size();
+
+ Node cur = tmpQueue.poll();
+ if (cur.left != null) tmpQueue.add(cur.left);
+ if (cur.right != null) tmpQueue.add(cur.right);
+
+ for (int index = 1; index < size; index++){
+ Node next = tmpQueue.poll();
+ if (next.left != null) tmpQueue.add(next.left);
+ if (next.right != null) tmpQueue.add(next.right);
+
+ cur.next = next;
+ cur = next;
+ }
+ }
+
+ return root;
+ }
+}
+```
python代码:
@@ -1254,7 +1312,8 @@ func connect(root *Node) *Node {
}
```
-## 117.填充每个节点的下一个右侧节点指针II
+# 117.填充每个节点的下一个右侧节点指针II
+
题目地址:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
@@ -1264,7 +1323,7 @@ func connect(root *Node) *Node {
C++代码:
-```C++
+```CPP
class Solution {
public:
Node* connect(Node* root) {
@@ -1295,6 +1354,44 @@ public:
}
};
```
+
+Java 代码:
+
+```java
+// 二叉树之层次遍历
+class Solution {
+ public Node connect(Node root) {
+ Queue queue = new LinkedList<>();
+ if (root != null) {
+ queue.add(root);
+ }
+ while (!queue.isEmpty()) {
+ int size = queue.size();
+ Node node = null;
+ Node nodePre = null;
+
+ for (int i = 0; i < size; i++) {
+ if (i == 0) {
+ nodePre = queue.poll(); // 取出本层头一个节点
+ node = nodePre;
+ } else {
+ node = queue.poll();
+ nodePre.next = node; // 本层前一个节点 next 指向当前节点
+ nodePre = nodePre.next;
+ }
+ if (node.left != null) {
+ queue.add(node.left);
+ }
+ if (node.right != null) {
+ queue.add(node.right);
+ }
+ }
+ nodePre.next = null; // 本层最后一个节点 next 指向 null
+ }
+ return root;
+ }
+}
+```
python代码:
```python
@@ -1378,12 +1475,119 @@ func connect(root *Node) *Node {
return root
}
```
+# 104.二叉树的最大深度
-## 总结
+题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
-二叉树的层序遍历,就是图论中的广度优先搜索在二叉树中的应用,需要借助队列来实现(此时是不是又发现队列的应用了)。
+给定一个二叉树,找出其最大深度。
-虽然不能一口气打十个,打八个也还行。
+二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
+
+说明: 叶子节点是指没有子节点的节点。
+
+示例:
+
+给定二叉树 [3,9,20,null,null,15,7],
+
+
+
+返回它的最大深度 3 。
+
+思路:
+
+使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
+
+在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:
+
+
+
+所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
+
+C++代码如下:
+
+```CPP
+class Solution {
+public:
+ int maxDepth(TreeNode* root) {
+ if (root == NULL) return 0;
+ int depth = 0;
+ queue que;
+ que.push(root);
+ while(!que.empty()) {
+ int size = que.size();
+ depth++; // 记录深度
+ for (int i = 0; i < size; i++) {
+ TreeNode* node = que.front();
+ que.pop();
+ if (node->left) que.push(node->left);
+ if (node->right) que.push(node->right);
+ }
+ }
+ return depth;
+ }
+};
+```
+
+Java:
+
+
+Python:
+
+Go:
+
+JavaScript:
+
+# 111.二叉树的最小深度
+
+相对于 104.二叉树的最大深度 ,本题还也可以使用层序遍历的方式来解决,思路是一样的。
+
+**需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点**
+
+代码如下:(详细注释)
+
+```CPP
+class Solution {
+public:
+ int minDepth(TreeNode* root) {
+ if (root == NULL) return 0;
+ int depth = 0;
+ queue que;
+ que.push(root);
+ while(!que.empty()) {
+ int size = que.size();
+ depth++; // 记录最小深度
+ for (int i = 0; i < size; i++) {
+ TreeNode* node = que.front();
+ que.pop();
+ if (node->left) que.push(node->left);
+ if (node->right) que.push(node->right);
+ if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
+ return depth;
+ }
+ }
+ }
+ return depth;
+ }
+};
+```
+
+Java:
+
+
+Python:
+
+Go:
+
+JavaScript:
+
+
+
+
+# 总结
+
+二叉树的层序遍历,**就是图论中的广度优先搜索在二叉树中的应用**,需要借助队列来实现(此时又发现队列的一个应用了)。
+
+来吧,一口气打十个:
* 102.二叉树的层序遍历
* 107.二叉树的层次遍历II
@@ -1393,289 +1597,15 @@ func connect(root *Node) *Node {
* 515.在每个树行中找最大值
* 116.填充每个节点的下一个右侧节点指针
* 117.填充每个节点的下一个右侧节点指针II
+* 104.二叉树的最大深度
+* 111.二叉树的最小深度
-如果非要打十个,还得找叶师傅!
-
-
+**致敬叶师傅!**
-
-# 其他语言版本
-
-
-> 二叉树的层序遍历(Javascript语言完全版) (迭代 + 递归)
-
-```js
-/**
- * 102. 二叉树的层序遍历
- * @param {TreeNode} root
- * @return {number[][]}
- */
-
-// 迭代
-
-var levelOrder = function(root) {
- const queue = [], res = [];
- root && queue.push(root);
- while(len = queue.length) {
- const val = [];
- while(len--) {
- const node = queue.shift();
- val.push(node.val);
- node.left && queue.push(node.left);
- node.right && queue.push(node.right);
- }
- res.push(val);
- }
- return res;
-};
-
-// 递归
-var levelOrder = function(root) {
- const res = [];
- function defs (root, i) {
- if(!root) return;
- if(!res[i]) res[i] = [];
- res[i].push(root.val)
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return res;
-};
-
-
-/**
- * 107. 二叉树的层序遍历 II
- * @param {TreeNode} root
- * @return {number[][]}
- */
-
-// 迭代
-
-var levelOrderBottom = function(root) {
- const queue = [], res = [];
- root && queue.push(root);
- while(len = queue.length) {
- const val = [];
- while(len--) {
- const node = queue.shift();
- val.push(node.val);
- node.left && queue.push(node.left);
- node.right && queue.push(node.right);
- }
- res.push(val);
- }
- return res.reverse()
-};
-
-// 递归
-
-var levelOrderBottom = function(root) {
- const res = [];
- function defs (root, i) {
- if(!root) return;
- if(!res[i]) res[i] = [];
- res[i].push(root.val);
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return res.reverse();
-};
-
-/**
- * 199. 二叉树的右视图
- * @param {TreeNode} root
- * @return {number[]}
- */
-
-// 迭代
-
-var rightSideView = function(root) {
- const res = [], queue = [];
- root && queue.push(root);
- while(l = queue.length) {
- while (l--) {
- const {val, left, right} = queue.shift();
- !l && res.push(val);
- left && queue.push(left);
- right && queue.push(right);
- }
- }
- return res;
-};
-
-// 递归
-var rightSideView = function(root) {
- const res = [];
- function defs(root, i) {
- if(!root) return;
- res[i] = root.val;
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return res;
-};
-
-/**
- * 637. 二叉树的层平均值
- * @param {TreeNode} root
- * @return {number[]}
- */
-
-// 迭代
-var averageOfLevels = function(root) {
- const queue = [], res = [];
- root && queue.push(root);
- while(len = queue.length) {
- let sum = 0, l = len;
- while(l--) {
- const {val, left, right} = queue.shift();
- sum += val;
- left && queue.push(left);
- right && queue.push(right);
- }
- res.push(sum/len);
- }
- return res;
-};
-
-// 递归
-var averageOfLevels = function(root) {
- const resCount = [], res = [];
- function defs(root, i) {
- if(!root) return;
- if(isNaN(res[i])) resCount[i] = res[i] = 0;
- res[i] += root.val;
- resCount[i]++;
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return res.map((val, i) => val / resCount[i]);
-};
-
-/**
- * 515. 在每个树行中找最大值
- * @param {TreeNode} root
- * @return {number[]}
- */
-
-// 迭代
-const MIN_G = Number.MIN_SAFE_INTEGER;
-var largestValues = function(root) {
- const queue = [], res = [];
- root && queue.push(root);
- while(len = queue.length) {
- let max = MIN_G;
- while(len--) {
- const {val, left, right} = queue.shift();
- max = max > val ? max : val;
- left && queue.push(left);
- right && queue.push(right);
- }
- res.push(max);
- }
- return res;
-};
-
-// 递归
-var largestValues = function(root) {
- const res = [];
- function defs (root, i) {
- if(!root) return;
- if(isNaN(res[i])) res[i] = root.val;
- res[i] = res[i] > root.val ? res[i] : root.val;
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return res;
-};
-
-/**
- * 429. N 叉树的层序遍历
- * @param {Node|null} root
- * @return {number[][]}
- */
-
-// 迭代
-var levelOrder = function(root) {
- const queue = [], res = [];
- root && queue.push(root);
- while(len = queue.length) {
- const vals = [];
- while(len--) {
- const {val, children} = queue.shift();
- vals.push(val);
- for(const e of children) {
- queue.push(e);
- }
- }
- res.push(vals);
- }
- return res;
-};
-
-// 递归
-
-var levelOrder = function(root) {
- const res = [];
- function defs (root, i) {
- if(!root) return;
- if(!res[i]) res[i] = [];
- res[i].push(root.val);
- for(const e of root.children) {
- defs(e, i + 1);
- }
- }
- defs(root, 0);
- return res;
-};
-
-/**
- * 116. 填充每个节点的下一个右侧节点指针
- * 117. 填充每个节点的下一个右侧节点指针 II
- * @param {Node} root
- * @return {Node}
- */
-
-// 迭代
-var connect = function(root) {
- const queue = [];
- root && queue.push(root);
- while(len = queue.length) {
- while(len--) {
- const node1 = queue.shift(),
- node2 = len ? queue[0] : null;
- node1.next = node2;
- node1.left && queue.push(node1.left);
- node1.right && queue.push(node1.right);
- }
- }
- return root;
-};
-
-// 递归
-var connect = function(root) {
- const res = [];
- function defs (root, i) {
- if(!root) return;
- if(res[i]) res[i].next = root;
- res[i] = root;
- root.left && defs(root.left, i + 1);
- root.right && defs(root.right, i + 1);
- }
- defs(root, 0);
- return root;
-};
-```
-
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md
index 218a966c..f09361e1 100644
--- a/problems/0104.二叉树的最大深度.md
+++ b/problems/0104.二叉树的最大深度.md
@@ -8,10 +8,11 @@
看完本篇可以一起做了如下两道题目:
-* 104.二叉树的最大深度
-* 559.N叉树的最大深度
-## 104.二叉树的最大深度
+* 104.二叉树的最大深度
+* 559.n叉树的最大深度
+
+# 104.二叉树的最大深度
题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
@@ -28,7 +29,7 @@
返回它的最大深度 3 。
-### 递归法
+## 递归法
本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
@@ -41,53 +42,53 @@
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。
代码如下:
-```
-int getDepth(TreeNode* node)
+```c++
+int getdepth(treenode* node)
```
2. 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
代码如下:
-```
-if (node == NULL) return 0;
+```c++
+if (node == null) return 0;
```
3. 确定单层递归的逻辑:先求它的左子树的深度,再求的右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。
代码如下:
-```
-int leftDepth = getDepth(node->left); // 左
-int rightDepth = getDepth(node->right); // 右
-int depth = 1 + max(leftDepth, rightDepth); // 中
+```c++
+int leftdepth = getdepth(node->left); // 左
+int rightdepth = getdepth(node->right); // 右
+int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
```
-所以整体C++代码如下:
+所以整体c++代码如下:
-```C++
-class Solution {
+```c++
+class solution {
public:
- int getDepth(TreeNode* node) {
- if (node == NULL) return 0;
- int leftDepth = getDepth(node->left); // 左
- int rightDepth = getDepth(node->right); // 右
- int depth = 1 + max(leftDepth, rightDepth); // 中
+ int getdepth(treenode* node) {
+ if (node == null) return 0;
+ int leftdepth = getdepth(node->left); // 左
+ int rightdepth = getdepth(node->right); // 右
+ int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
}
- int maxDepth(TreeNode* root) {
- return getDepth(root);
+ int maxdepth(treenode* root) {
+ return getdepth(root);
}
};
```
-代码精简之后C++代码如下:
-```C++
-class Solution {
+代码精简之后c++代码如下:
+```c++
+class solution {
public:
- int maxDepth(TreeNode* root) {
- if (root == NULL) return 0;
- return 1 + max(maxDepth(root->left), maxDepth(root->right));
+ int maxdepth(treenode* root) {
+ if (root == null) return 0;
+ return 1 + max(maxdepth(root->left), maxdepth(root->right));
}
};
@@ -98,31 +99,31 @@ public:
本题当然也可以使用前序,代码如下:(**充分表现出求深度回溯的过程**)
-```C++
-class Solution {
+```c++
+class solution {
public:
int result;
- void getDepth(TreeNode* node, int depth) {
+ void getdepth(treenode* node, int depth) {
result = depth > result ? depth : result; // 中
- if (node->left == NULL && node->right == NULL) return ;
+ if (node->left == null && node->right == null) return ;
if (node->left) { // 左
depth++; // 深度+1
- getDepth(node->left, depth);
+ getdepth(node->left, depth);
depth--; // 回溯,深度-1
}
if (node->right) { // 右
depth++; // 深度+1
- getDepth(node->right, depth);
+ getdepth(node->right, depth);
depth--; // 回溯,深度-1
}
return ;
}
- int maxDepth(TreeNode* root) {
+ int maxdepth(treenode* root) {
result = 0;
if (root == 0) return result;
- getDepth(root, 1);
+ getdepth(root, 1);
return result;
}
};
@@ -132,31 +133,31 @@ public:
注意以上代码是为了把细节体现出来,简化一下代码如下:
-```C++
-class Solution {
+```c++
+class solution {
public:
int result;
- void getDepth(TreeNode* node, int depth) {
+ void getdepth(treenode* node, int depth) {
result = depth > result ? depth : result; // 中
- if (node->left == NULL && node->right == NULL) return ;
+ if (node->left == null && node->right == null) return ;
if (node->left) { // 左
- getDepth(node->left, depth + 1);
+ getdepth(node->left, depth + 1);
}
if (node->right) { // 右
- getDepth(node->right, depth + 1);
+ getdepth(node->right, depth + 1);
}
return ;
}
- int maxDepth(TreeNode* root) {
+ int maxdepth(treenode* root) {
result = 0;
if (root == 0) return result;
- getDepth(root, 1);
+ getdepth(root, 1);
return result;
}
};
```
-### 迭代法
+## 迭代法
使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
@@ -166,23 +167,23 @@ public:
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
-如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)
+如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
-C++代码如下:
+c++代码如下:
-```C++
-class Solution {
+```c++
+class solution {
public:
- int maxDepth(TreeNode* root) {
- if (root == NULL) return 0;
+ int maxdepth(treenode* root) {
+ if (root == null) return 0;
int depth = 0;
- queue que;
+ queue que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录深度
for (int i = 0; i < size; i++) {
- TreeNode* node = que.front();
+ treenode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
@@ -193,19 +194,19 @@ public:
};
```
-那么我们可以顺便解决一下N叉树的最大深度问题
+那么我们可以顺便解决一下n叉树的最大深度问题
-## 559.N叉树的最大深度
+# 559.n叉树的最大深度
题目地址:https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
-给定一个 N 叉树,找到其最大深度。
+给定一个 n 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
例如,给定一个 3叉树 :
-
+
我们应返回其最大深度,3。
@@ -213,39 +214,39 @@ public:
依然可以提供递归法和迭代法,来解决这个问题,思路是和二叉树思路一样的,直接给出代码如下:
-### 递归法
+## 递归法
-C++代码:
+c++代码:
-```C++
-class Solution {
+```c++
+class solution {
public:
- int maxDepth(Node* root) {
+ int maxdepth(node* root) {
if (root == 0) return 0;
int depth = 0;
for (int i = 0; i < root->children.size(); i++) {
- depth = max (depth, maxDepth(root->children[i]));
+ depth = max (depth, maxdepth(root->children[i]));
}
return depth + 1;
}
};
```
-### 迭代法
+## 迭代法
依然是层序遍历,代码如下:
-```C++
-class Solution {
+```c++
+class solution {
public:
- int maxDepth(Node* root) {
- queue que;
- if (root != NULL) que.push(root);
+ int maxdepth(node* root) {
+ queue que;
+ if (root != null) que.push(root);
int depth = 0;
while (!que.empty()) {
int size = que.size();
depth++; // 记录深度
for (int i = 0; i < size; i++) {
- Node* node = que.front();
+ node* node = que.front();
que.pop();
for (int j = 0; j < node->children.size(); j++) {
if (node->children[j]) que.push(node->children[j]);
@@ -257,45 +258,46 @@ public:
};
```
-## 其他语言版本
+# 其他语言版本
+## java
-Java:
+### 104.二叉树的最大深度
-```Java
-class Solution {
+```java
+class solution {
/**
* 递归法
*/
- public int maxDepth(TreeNode root) {
+ public int maxdepth(treenode root) {
if (root == null) {
return 0;
}
- int leftDepth = maxDepth(root.left);
- int rightDepth = maxDepth(root.right);
- return Math.max(leftDepth, rightDepth) + 1;
+ int leftdepth = maxdepth(root.left);
+ int rightdepth = maxdepth(root.right);
+ return math.max(leftdepth, rightdepth) + 1;
}
}
```
-```Java
-class Solution {
+```java
+class solution {
/**
* 迭代法,使用层序遍历
*/
- public int maxDepth(TreeNode root) {
+ public int maxdepth(treenode root) {
if(root == null) {
return 0;
}
- Deque deque = new LinkedList<>();
+ deque deque = new linkedlist<>();
deque.offer(root);
int depth = 0;
- while (!deque.isEmpty()) {
+ while (!deque.isempty()) {
int size = deque.size();
depth++;
for (int i = 0; i < size; i++) {
- TreeNode poll = deque.poll();
+ treenode poll = deque.poll();
if (poll.left != null) {
deque.offer(poll.left);
}
@@ -309,37 +311,39 @@ class Solution {
}
```
-Python:
+## python
-104.二叉树的最大深度
-> 递归法:
+### 104.二叉树的最大深度
+
+递归法:
```python
-class Solution:
- def maxDepth(self, root: TreeNode) -> int:
- return self.getDepth(root)
+class solution:
+ def maxdepth(self, root: treenode) -> int:
+ return self.getdepth(root)
- def getDepth(self, node):
+ def getdepth(self, node):
if not node:
return 0
- leftDepth = self.getDepth(node.left) #左
- rightDepth = self.getDepth(node.right) #右
- depth = 1 + max(leftDepth, rightDepth) #中
+ leftdepth = self.getdepth(node.left) #左
+ rightdepth = self.getdepth(node.right) #右
+ depth = 1 + max(leftdepth, rightdepth) #中
return depth
```
-> 递归法;精简代码
+
+递归法:精简代码
```python
-class Solution:
- def maxDepth(self, root: TreeNode) -> int:
+class solution:
+ def maxdepth(self, root: treenode) -> int:
if not root:
return 0
- return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))
+ return 1 + max(self.maxdepth(root.left), self.maxdepth(root.right))
```
-> 迭代法:
+迭代法:
```python
import collections
-class Solution:
- def maxDepth(self, root: TreeNode) -> int:
+class solution:
+ def maxdepth(self, root: treenode) -> int:
if not root:
return 0
depth = 0 #记录深度
@@ -357,24 +361,25 @@ class Solution:
return depth
```
-559.N叉树的最大深度
-> 递归法:
+### 559.n叉树的最大深度
+
+递归法:
```python
-class Solution:
- def maxDepth(self, root: 'Node') -> int:
+class solution:
+ def maxdepth(self, root: 'node') -> int:
if not root:
return 0
depth = 0
for i in range(len(root.children)):
- depth = max(depth, self.maxDepth(root.children[i]))
+ depth = max(depth, self.maxdepth(root.children[i]))
return depth + 1
```
-> 迭代法:
+迭代法:
```python
import collections
-class Solution:
- def maxDepth(self, root: 'Node') -> int:
+class solution:
+ def maxdepth(self, root: 'node') -> int:
queue = collections.deque()
if root:
queue.append(root)
@@ -390,10 +395,10 @@ class Solution:
return depth
```
-> 使用栈来模拟后序遍历依然可以
+使用栈来模拟后序遍历依然可以
```python
-class Solution:
- def maxDepth(self, root: 'Node') -> int:
+class solution:
+ def maxdepth(self, root: 'node') -> int:
st = []
if root:
st.append(root)
@@ -401,9 +406,9 @@ class Solution:
result = 0
while st:
node = st.pop()
- if node != None:
+ if node != none:
st.append(node) #中
- st.append(None)
+ st.append(none)
depth += 1
for i in range(len(node.children)): #处理孩子
if node.children[i]:
@@ -417,15 +422,15 @@ class Solution:
```
-Go:
+## go
```go
/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
+ * definition for a binary tree node.
+ * type treenode struct {
+ * val int
+ * left *treenode
+ * right *treenode
* }
*/
func max (a, b int) int {
@@ -435,28 +440,28 @@ func max (a, b int) int {
return b;
}
// 递归
-func maxDepth(root *TreeNode) int {
+func maxdepth(root *treenode) int {
if root == nil {
return 0;
}
- return max(maxDepth(root.Left), maxDepth(root.Right)) + 1;
+ return max(maxdepth(root.left), maxdepth(root.right)) + 1;
}
// 遍历
-func maxDepth(root *TreeNode) int {
+func maxdepth(root *treenode) int {
levl := 0;
- queue := make([]*TreeNode, 0);
+ queue := make([]*treenode, 0);
if root != nil {
queue = append(queue, root);
}
for l := len(queue); l > 0; {
for ;l > 0;l-- {
node := queue[0];
- if node.Left != nil {
- queue = append(queue, node.Left);
+ if node.left != nil {
+ queue = append(queue, node.left);
}
- if node.Right != nil {
- queue = append(queue, node.Right);
+ if node.right != nil {
+ queue = append(queue, node.right);
}
queue = queue[1:];
}
@@ -469,46 +474,49 @@ func maxDepth(root *TreeNode) int {
```
-JavaScript
+## javascript
+
```javascript
-var maxDepth = function(root) {
+var maxdepth = function(root) {
if (!root) return root
- return 1 + Math.max(maxDepth(root.left), maxDepth(root.right))
+ return 1 + math.max(maxdepth(root.left), maxdepth(root.right))
};
-```
+```
+
二叉树最大深度递归遍历
```javascript
-var maxDepth = function(root) {
+var maxdepth = function(root) {
//使用递归的方法 递归三部曲
//1. 确定递归函数的参数和返回值
- const getDepth=function(node){
+ const getdepth=function(node){
//2. 确定终止条件
if(node===null){
return 0;
}
//3. 确定单层逻辑
- let leftDepth=getDepth(node.left);
- let rightDepth=getDepth(node.right);
- let depth=1+Math.max(leftDepth,rightDepth);
+ let leftdepth=getdepth(node.left);
+ let rightdepth=getdepth(node.right);
+ let depth=1+math.max(leftdepth,rightdepth);
return depth;
}
- return getDepth(root);
+ return getdepth(root);
};
```
+
二叉树最大深度层级遍历
```javascript
-var maxDepth = function(root) {
+var maxdepth = function(root) {
//使用递归的方法 递归三部曲
//1. 确定递归函数的参数和返回值
- const getDepth=function(node){
+ const getdepth=function(node){
//2. 确定终止条件
if(node===null){
return 0;
}
//3. 确定单层逻辑
- let leftDepth=getDepth(node.left);
- let rightDepth=getDepth(node.right);
- let depth=1+Math.max(leftDepth,rightDepth);
+ let leftdepth=getdepth(node.left);
+ let rightdepth=getdepth(node.right);
+ let depth=1+math.max(leftdepth,rightdepth);
return depth;
}
return getDepth(root);
@@ -519,4 +527,4 @@ var maxDepth = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md
index 4c5a70a0..4cfe2858 100644
--- a/problems/0106.从中序与后序遍历序列构造二叉树.md
+++ b/problems/0106.从中序与后序遍历序列构造二叉树.md
@@ -59,7 +59,7 @@
不难写出如下代码:(先把框架写出来)
-```C++
+```CPP
TreeNode* traversal (vector& inorder, vector& postorder) {
// 第一步
@@ -155,7 +155,7 @@ root->right = traversal(rightInorder, rightPostorder);
### C++完整代码
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal (vector& inorder, vector& postorder) {
@@ -209,7 +209,7 @@ public:
加了日志的代码如下:(加了日志的代码不要在leetcode上提交,容易超时)
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal (vector& inorder, vector& postorder) {
@@ -277,7 +277,7 @@ public:
下面给出用下表索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下表索引来分割)
### C++优化版本
-```C++
+```CPP
class Solution {
private:
// 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
@@ -325,7 +325,7 @@ public:
那么这个版本写出来依然要打日志进行调试,打日志的版本如下:(**该版本不要在leetcode上提交,容易超时**)
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal (vector& inorder, int inorderBegin, int inorderEnd, vector& postorder, int postorderBegin, int postorderEnd) {
@@ -419,7 +419,7 @@ public:
带日志的版本C++代码如下: (**带日志的版本仅用于调试,不要在leetcode上提交,会超时**)
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal (vector& inorder, int inorderBegin, int inorderEnd, vector& preorder, int preorderBegin, int preorderEnd) {
@@ -493,7 +493,7 @@ public:
105.从前序与中序遍历序列构造二叉树,最后版本,C++代码:
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal (vector& inorder, int inorderBegin, int inorderEnd, vector& preorder, int preorderBegin, int preorderEnd) {
@@ -654,43 +654,68 @@ class Solution {
```
Python:
+
105.从前序与中序遍历序列构造二叉树
```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 buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
- if not preorder: return None //特殊情况
- root = TreeNode(preorder[0]) //新建父节点
- p=inorder.index(preorder[0]) //找到父节点在中序遍历的位置(因为没有重复的元素,才可以这样找)
- root.left = self.buildTree(preorder[1:p+1],inorder[:p]) //注意左节点时分割中序数组和前续数组的开闭环
- root.right = self.buildTree(preorder[p+1:],inorder[p+1:]) //分割中序数组和前续数组
- return root
+ # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
+ if not preorder:
+ return None
+
+ # 第二步: 前序遍历的第一个就是当前的中间节点.
+ root_val = preorder[0]
+ root = TreeNode(root_val)
+
+ # 第三步: 找切割点.
+ separator_idx = inorder.index(root_val)
+
+ # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
+ inorder_left = inorder[:separator_idx]
+ inorder_right = inorder[separator_idx + 1:]
+
+ # 第五步: 切割preorder数组. 得到preorder数组的左,右半边.
+ # ⭐️ 重点1: 中序数组大小一定跟前序数组大小是相同的.
+ preorder_left = preorder[1:1 + len(inorder_left)]
+ preorder_right = preorder[1 + len(inorder_left):]
+
+ # 第六步: 递归
+ root.left = self.buildTree(preorder_left, inorder_left)
+ root.right = self.buildTree(preorder_right, inorder_right)
+
+ return root
```
106.从中序与后序遍历序列构造二叉树
```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 buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
- if not postorder: return None //特殊情况
- root = TreeNode(postorder[-1]) //新建父节点
- p=inorder.index(postorder[-1]) //找到父节点在中序遍历的位置*因为没有重复的元素,才可以这样找
- root.left = self.buildTree(inorder[:p],postorder[:p]) //分割中序数组和后续数组
- root.right = self.buildTree(inorder[p+1:],postorder[p:-1]) //注意右节点时分割中序数组和后续数组的开闭环
- return root
+ # 第一步: 特殊情况讨论: 树为空. (递归终止条件)
+ if not postorder:
+ return None
+
+ # 第二步: 后序遍历的最后一个就是当前的中间节点.
+ root_val = postorder[-1]
+ root = TreeNode(root_val)
+
+ # 第三步: 找切割点.
+ separator_idx = inorder.index(root_val)
+
+ # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
+ inorder_left = inorder[:separator_idx]
+ inorder_right = inorder[separator_idx + 1:]
+
+ # 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
+ # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
+ postorder_left = postorder[:len(inorder_left)]
+ postorder_right = postorder[len(inorder_left): len(postorder) - 1]
+
+ # 第六步: 递归
+ root.left = self.buildTree(inorder_left, postorder_left)
+ root.right = self.buildTree(inorder_right, postorder_right)
+
+ return root
```
Go:
> 106 从中序与后序遍历序列构造二叉树
@@ -793,4 +818,4 @@ var buildTree = function(preorder, inorder) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md
index 8ec5f3dc..9e67a677 100644
--- a/problems/0108.将有序数组转换为二叉搜索树.md
+++ b/problems/0108.将有序数组转换为二叉搜索树.md
@@ -122,7 +122,7 @@ return root;
* 递归整体代码如下:
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal(vector& nums, int left, int right) {
@@ -150,7 +150,7 @@ public:
模拟的就是不断分割的过程,C++代码如下:(我已经详细注释)
-```C++
+```CPP
class Solution {
public:
TreeNode* sortedArrayToBST(vector& nums) {
@@ -388,4 +388,4 @@ var sortedArrayToBST = function (nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md
index b6e50853..55d3c2e7 100644
--- a/problems/0110.平衡二叉树.md
+++ b/problems/0110.平衡二叉树.md
@@ -9,7 +9,7 @@
> 求高度还是求深度,你搞懂了不?
-## 110.平衡二叉树
+# 110.平衡二叉树
题目地址:https://leetcode-cn.com/problems/balanced-binary-tree/
@@ -33,9 +33,10 @@
返回 false 。
-## 题外话
+# 题外话
-咋眼一看这道题目和[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)很像,其实有很大区别。
+
+咋眼一看这道题目和[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)很像,其实有很大区别。
这里强调一波概念:
@@ -50,13 +51,13 @@
因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
-有的同学一定疑惑,为什么[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)中求的是二叉树的最大深度,也用的是后序遍历。
+有的同学一定疑惑,为什么[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中求的是二叉树的最大深度,也用的是后序遍历。
**那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这颗树的最大深度,所以才可以使用后序遍历。**
-在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
+在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
-```C++
+```CPP
class Solution {
public:
int result;
@@ -90,7 +91,7 @@ public:
注意以上代码是为了把细节体现出来,简化一下代码如下:
-```C++
+```CPP
class Solution {
public:
int result;
@@ -114,9 +115,9 @@ public:
};
```
-## 本题思路
+# 本题思路
-### 递归
+## 递归
此时大家应该明白了既然要求比较高度,必然是要后序遍历。
@@ -160,7 +161,7 @@ if (node == NULL) {
代码如下:
-```
+```CPP
int leftDepth = depth(node->left); // 左
if (leftDepth == -1) return -1;
int rightDepth = depth(node->right); // 右
@@ -178,7 +179,7 @@ return result;
代码精简之后如下:
-```
+```CPP
int leftDepth = getDepth(node->left);
if (leftDepth == -1) return -1;
int rightDepth = getDepth(node->right);
@@ -190,7 +191,7 @@ return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
getDepth整体代码如下:
-```C++
+```CPP
int getDepth(TreeNode* node) {
if (node == NULL) {
return 0;
@@ -205,7 +206,7 @@ int getDepth(TreeNode* node) {
最后本题整体递归代码如下:
-```C++
+```CPP
class Solution {
public:
// 返回以该节点为根节点的二叉树的高度,如果不是二叉搜索树了则返回-1
@@ -225,9 +226,9 @@ public:
};
```
-### 迭代
+## 迭代
-在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
+在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
本题的迭代方式可以先定义一个函数,专门用来求高度。
@@ -235,7 +236,7 @@ public:
代码如下:
-```C++
+```CPP
// cur节点的最大深度,就是cur的高度
int getDepth(TreeNode* cur) {
stack st;
@@ -266,7 +267,7 @@ int getDepth(TreeNode* cur) {
然后再用栈来模拟前序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,代码如下:
-```
+```CPP
bool isBalanced(TreeNode* root) {
stack st;
if (root == NULL) return true;
@@ -286,7 +287,7 @@ bool isBalanced(TreeNode* root) {
整体代码如下:
-```
+```CPP
class Solution {
private:
int getDepth(TreeNode* cur) {
@@ -342,7 +343,7 @@ public:
因为对于回溯算法已经是非常复杂的递归了,如果在用迭代的话,就是自己给自己找麻烦,效率也并不一定高。
-## 总结
+# 总结
通过本题可以了解求二叉树深度 和 二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历。
@@ -351,9 +352,9 @@ public:
但是递归方式是一定要掌握的!
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -494,9 +495,9 @@ class Solution {
}
```
-Python:
+## Python
-> 递归法:
+递归法:
```python
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
@@ -513,7 +514,7 @@ class Solution:
return -1 if abs(leftDepth - rightDepth)>1 else 1 + max(leftDepth, rightDepth)
```
-> 迭代法:
+迭代法:
```python
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
@@ -553,7 +554,7 @@ class Solution:
```
-Go:
+## Go
```Go
func isBalanced(root *TreeNode) bool {
if root==nil{
@@ -589,7 +590,7 @@ func abs(a int)int{
}
```
-JavaScript:
+## JavaScript
```javascript
var isBalanced = function(root) {
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
@@ -623,4 +624,4 @@ var isBalanced = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md
index a36faeff..b4d0e32b 100644
--- a/problems/0111.二叉树的最小深度.md
+++ b/problems/0111.二叉树的最小深度.md
@@ -9,7 +9,7 @@
> 和求最大深度一个套路?
-## 111.二叉树的最小深度
+# 111.二叉树的最小深度
题目地址:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
@@ -27,9 +27,9 @@
返回它的最小深度 2.
-## 思路
+# 思路
-看完了这篇[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg),再来看看如何求最小深度。
+看完了这篇[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),再来看看如何求最小深度。
直觉上好像和求最大深度差不多,其实还是差不少的。
@@ -87,7 +87,7 @@ return result;
代码如下:
-```C++
+```CPP
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
// 中
@@ -106,7 +106,7 @@ return result;
遍历的顺序为后序(左右中),可以看出:**求二叉树的最小深度和求二叉树的最大深度的差别主要在于处理左右孩子不为空的逻辑。**
整体递归代码如下:
-```C++
+```CPP
class Solution {
public:
int getDepth(TreeNode* node) {
@@ -134,7 +134,7 @@ public:
精简之后代码如下:
-```C++
+```CPP
class Solution {
public:
int minDepth(TreeNode* root) {
@@ -154,15 +154,15 @@ public:
## 迭代法
-相对于[104.二叉树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg),本题还可以使用层序遍历的方式来解决,思路是一样的。
+相对于[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),本题还可以使用层序遍历的方式来解决,思路是一样的。
-如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)
+如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
**需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点**
代码如下:(详细注释)
-```C++
+```CPP
class Solution {
public:
@@ -190,10 +190,10 @@ public:
```
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -253,7 +253,7 @@ class Solution {
}
```
-Python:
+## Python
递归法:
@@ -299,7 +299,7 @@ class Solution:
```
-Go:
+## Go
```go
/**
@@ -360,7 +360,7 @@ func minDepth(root *TreeNode) int {
```
-JavaScript:
+## JavaScript
递归法:
@@ -413,4 +413,4 @@ var minDepth = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md
index ae9a9267..4a814ee1 100644
--- a/problems/0112.路径总和.md
+++ b/problems/0112.路径总和.md
@@ -9,14 +9,14 @@
> 递归函数什么时候需要返回值
-相信很多同学都会疑惑,递归函数什么时候要有返回值,什么时候没有返回值,特别是有的时候递归函数返回类型为bool类型。那么
+相信很多同学都会疑惑,递归函数什么时候要有返回值,什么时候没有返回值,特别是有的时候递归函数返回类型为bool类型。
-接下来我通过详细讲解如下两道题,来回答这个问题:
+那么接下来我通过详细讲解如下两道题,来回答这个问题:
* 112.路径总和
-* 113.路径总和II
+* 113.路径总和ii
-## 112. 路径总和
+# 112. 路径总和
题目地址:https://leetcode-cn.com/problems/path-sum/
@@ -31,11 +31,11 @@
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
-### 思路
+# 思路
这道题我们要遍历从根节点到叶子节点的的路径看看总和是不是目标和。
-### 递归
+## 递归
可以使用深度优先遍历的方式(本题前中后序都可以,无所谓,因为中节点也没有处理逻辑)来遍历二叉树
@@ -43,13 +43,11 @@
参数:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和,计数器为int型。
-**再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?**
+再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
-在文章[二叉树:我的左下角的值是多少?](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw)中,我给出了一个结论:
-
-**如果需要搜索整颗二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。**
-
-在[二叉树:我的左下角的值是多少?](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw)中,因为要遍历树的所有路径,找出深度最深的叶子节点,所以递归函数不要返回值。
+* 如果需要搜索整颗二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
+* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中介绍)
+* 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
而本题我们要找一条符合条件的路径,所以递归函数需要返回值,及时返回,那么返回类型是什么呢?
@@ -62,7 +60,7 @@
所以代码如下:
```
-bool traversal(TreeNode* cur, int count) // 注意函数的返回类型
+bool traversal(treenode* cur, int count) // 注意函数的返回类型
```
@@ -91,7 +89,7 @@ if (!cur->left && !cur->right) return false; // 遇到叶子节点而没有找
代码如下:
-```C++
+```cpp
if (cur->left) { // 左 (空节点不遍历)
// 遇到叶子节点返回true,则直接返回true
if (traversal(cur->left, count - cur->left->val)) return true; // 注意这里有回溯的逻辑
@@ -109,7 +107,7 @@ return false;
为了把回溯的过程体现出来,可以改为如下代码:
-```C++
+```cpp
if (cur->left) { // 左
count -= cur->left->val; // 递归,处理节点;
if (traversal(cur->left, count)) return true;
@@ -126,10 +124,10 @@ return false;
整体代码如下:
-```C++
-class Solution {
+```cpp
+class solution {
private:
- bool traversal(TreeNode* cur, int count) {
+ bool traversal(treenode* cur, int count) {
if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回
@@ -147,8 +145,8 @@ private:
}
public:
- bool hasPathSum(TreeNode* root, int sum) {
- if (root == NULL) return false;
+ bool haspathsum(treenode* root, int sum) {
+ if (root == null) return false;
return traversal(root, sum - root->val);
}
};
@@ -156,15 +154,15 @@ public:
以上代码精简之后如下:
-```C++
-class Solution {
+```cpp
+class solution {
public:
- bool hasPathSum(TreeNode* root, int sum) {
- if (root == NULL) return false;
+ bool haspathsum(treenode* root, int sum) {
+ if (root == null) return false;
if (!root->left && !root->right && sum == root->val) {
return true;
}
- return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
+ return haspathsum(root->left, sum - root->val) || haspathsum(root->right, sum - root->val);
}
};
```
@@ -172,43 +170,43 @@ public:
**是不是发现精简之后的代码,已经完全看不出分析的过程了,所以我们要把题目分析清楚之后,在追求代码精简。** 这一点我已经强调很多次了!
-### 迭代
+## 迭代
如果使用栈模拟递归的话,那么如果做回溯呢?
**此时栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和。**
-C++就我们用pair结构来存放这个栈里的元素。
+c++就我们用pair结构来存放这个栈里的元素。
-定义为:`pair` pair<节点指针,路径数值>
+定义为:`pair` pair<节点指针,路径数值>
这个为栈里的一个元素。
如下代码是使用栈模拟的前序遍历,如下:(详细注释)
-```C++
-class Solution {
+```cpp
+class solution {
public:
- bool hasPathSum(TreeNode* root, int sum) {
- if (root == NULL) return false;
+ bool haspathsum(treenode* root, int sum) {
+ if (root == null) return false;
// 此时栈里要放的是pair<节点指针,路径数值>
- stack> st;
- st.push(pair(root, root->val));
+ stack> st;
+ st.push(pair(root, root->val));
while (!st.empty()) {
- pair node = st.top();
+ pair node = st.top();
st.pop();
// 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
if (!node.first->left && !node.first->right && sum == node.second) return true;
// 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if (node.first->right) {
- st.push(pair(node.first->right, node.second + node.first->right->val));
+ st.push(pair(node.first->right, node.second + node.first->right->val));
}
// 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if (node.first->left) {
- st.push(pair(node.first->left, node.second + node.first->left->val));
+ st.push(pair(node.first->left, node.second + node.first->left->val));
}
}
return false;
@@ -216,9 +214,9 @@ public:
};
```
-如果大家完全理解了本地的递归方法之后,就可以顺便把leetcode上113. 路径总和II做了。
+如果大家完全理解了本地的递归方法之后,就可以顺便把leetcode上113. 路径总和ii做了。
-## 113. 路径总和II
+# 113. 路径总和ii
题目地址:https://leetcode-cn.com/problems/path-sum-ii/
@@ -230,26 +228,27 @@ public:
给定如下二叉树,以及目标和 sum = 22,
-
+
-### 思路
+## 思路
-113.路径总和II要遍历整个树,找到所有路径,**所以递归函数不要返回值!**
+
+113.路径总和ii要遍历整个树,找到所有路径,**所以递归函数不要返回值!**
如图:
-
+
为了尽可能的把细节体现出来,我写出如下代码(**这份代码并不简洁,但是逻辑非常清晰**)
-```C++
-class Solution {
+```cpp
+class solution {
private:
vector> result;
vector path;
// 递归函数不需要返回值,因为我们要遍历整个树
- void traversal(TreeNode* cur, int count) {
+ void traversal(treenode* cur, int count) {
if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为sum的路径
result.push_back(path);
return;
@@ -275,10 +274,10 @@ private:
}
public:
- vector> pathSum(TreeNode* root, int sum) {
+ vector> pathsum(treenode* root, int sum) {
result.clear();
path.clear();
- if (root == NULL) return result;
+ if (root == null) return result;
path.push_back(root->val); // 把根节点放进路径
traversal(root, sum - root->val);
return result;
@@ -286,11 +285,11 @@ public:
};
```
-至于113. 路径总和II 的迭代法我并没有写,用迭代方式记录所有路径比较麻烦,也没有必要,如果大家感兴趣的话,可以再深入研究研究。
+至于113. 路径总和ii 的迭代法我并没有写,用迭代方式记录所有路径比较麻烦,也没有必要,如果大家感兴趣的话,可以再深入研究研究。
-## 总结
+# 总结
-本篇通过leetcode上112. 路径总和 和 113. 路径总和II 详细的讲解了 递归函数什么时候需要返回值,什么不需要返回值。
+本篇通过leetcode上112. 路径总和 和 113. 路径总和ii 详细的讲解了 递归函数什么时候需要返回值,什么不需要返回值。
这两道题目是掌握这一知识点非常好的题目,大家看完本篇文章再去做题,就会感受到搜索整棵树和搜索某一路径的差别。
@@ -299,31 +298,30 @@ public:
+# 其他语言版本
+## java
-## 其他语言版本
-
-
-Java:
-```Java
-class Solution {
- public boolean hasPathSum(TreeNode root, int targetSum) {
+lc112
+```java
+class solution {
+ public boolean haspathsum(treenode root, int targetsum) {
if (root == null) {
return false;
}
- targetSum -= root.val;
+ targetsum -= root.val;
// 叶子结点
if (root.left == null && root.right == null) {
- return targetSum == 0;
+ return targetsum == 0;
}
if (root.left != null) {
- boolean left = hasPathSum(root.left, targetSum);
+ boolean left = haspathsum(root.left, targetsum);
if (left) {// 已经找到
return true;
}
}
if (root.right != null) {
- boolean right = hasPathSum(root.right, targetSum);
+ boolean right = haspathsum(root.right, targetsum);
if (right) {// 已经找到
return true;
}
@@ -332,34 +330,34 @@ class Solution {
}
}
-// LC112 简洁方法
-class Solution {
- public boolean hasPathSum(TreeNode root, int targetSum) {
+// lc112 简洁方法
+class solution {
+ public boolean haspathsum(treenode root, int targetsum) {
if (root == null) return false; // 为空退出
// 叶子节点判断是否符合
- if (root.left == null && root.right == null) return root.val == targetSum;
+ if (root.left == null && root.right == null) return root.val == targetsum;
// 求两侧分支的路径和
- return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
+ return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
}
}
```
迭代
```java
-class Solution {
- public boolean hasPathSum(TreeNode root, int targetSum) {
+class solution {
+ public boolean haspathsum(treenode root, int targetsum) {
if(root==null)return false;
- Stack stack1 = new Stack<>();
- Stack stack2 = new Stack<>();
+ stack stack1 = new stack<>();
+ stack stack2 = new stack<>();
stack1.push(root);stack2.push(root.val);
- while(!stack1.isEmpty()){
+ while(!stack1.isempty()){
int size = stack1.size();
for(int i=0;i> pathSum(TreeNode root, int targetSum) {
- List> res = new ArrayList<>();
+class solution {
+ public list> pathsum(treenode root, int targetsum) {
+ list> res = new arraylist<>();
if (root == null) return res; // 非空判断
- List path = new LinkedList<>();
- preorderDFS(root, targetSum, res, path);
+ list path = new linkedlist<>();
+ preorderdfs(root, targetsum, res, path);
return res;
}
- public void preorderDFS(TreeNode root, int targetSum, List> res, List path) {
+ public void preorderdfs(treenode root, int targetsum, list> res, list path) {
path.add(root.val);
// 遇到了叶子节点
if (root.left == null && root.right == null) {
- // 找到了和为 targetSum 的路径
- if (targetSum - root.val == 0) {
- res.add(new ArrayList<>(path));
+ // 找到了和为 targetsum 的路径
+ if (targetsum - root.val == 0) {
+ res.add(new arraylist<>(path));
}
- return; // 如果和不为 targetSum,返回
+ return; // 如果和不为 targetsum,返回
}
if (root.left != null) {
- preorderDFS(root.left, targetSum - root.val, res, path);
+ preorderdfs(root.left, targetsum - root.val, res, path);
path.remove(path.size() - 1); // 回溯
}
if (root.right != null) {
- preorderDFS(root.right, targetSum - root.val, res, path);
+ preorderdfs(root.right, targetsum - root.val, res, path);
path.remove(path.size() - 1); // 回溯
}
}
}
```
-Python:
+## python
0112.路径总和
+
+**递归**
```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 hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
- def isornot(root,targetSum)->bool:
- if (not root.left) and (not root.right) and targetSum == 0:return True // 遇到叶子节点,并且计数为0
- if (not root.left) and (not root.right):return False //遇到叶子节点,计数不为0
+class solution:
+ def haspathsum(self, root: treenode, targetsum: int) -> bool:
+ def isornot(root, targetsum) -> bool:
+ if (not root.left) and (not root.right) and targetsum == 0:
+ return true # 遇到叶子节点,并且计数为0
+ if (not root.left) and (not root.right):
+ return false # 遇到叶子节点,计数不为0
if root.left:
- targetSum -= root.left.val //左节点
- if isornot(root.left,targetSum):return True //递归,处理左节点
- targetSum += root.left.val //回溯
+ targetsum -= root.left.val # 左节点
+ if isornot(root.left, targetsum): return true # 递归,处理左节点
+ targetsum += root.left.val # 回溯
if root.right:
- targetSum -= root.right.val //右节点
- if isornot(root.right,targetSum):return True //递归,处理右节点
- targetSum += root.right.val //回溯
- return False
-
- if root == None:return False //别忘记处理空TreeNode
- else:return isornot(root,targetSum-root.val)
+ targetsum -= root.right.val # 右节点
+ if isornot(root.right, targetsum): return true # 递归,处理右节点
+ targetsum += root.right.val # 回溯
+ return false
+
+ if root == none:
+ return false # 别忘记处理空treenode
+ else:
+ return isornot(root, targetsum - root.val)
+```
+
+**迭代 - 层序遍历**
+```python
+class solution:
+ def haspathsum(self, root: treenode, targetsum: int) -> bool:
+ if not root:
+ return false
+
+ stack = [] # [(当前节点,路径数值), ...]
+ stack.append((root, root.val))
+
+ while stack:
+ cur_node, path_sum = stack.pop()
+
+ if not cur_node.left and not cur_node.right and path_sum == targetsum:
+ return true
+
+ if cur_node.right:
+ stack.append((cur_node.right, path_sum + cur_node.right.val))
+
+ if cur_node.left:
+ stack.append((cur_node.left, path_sum + cur_node.left.val))
+
+ return false
```
0113.路径总和-ii
+
+**递归**
```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 pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
- path=[]
- res=[]
- def pathes(root,targetSum):
- if (not root.left) and (not root.right) and targetSum == 0: // 遇到叶子节点,并且计数为0
- res.append(path[:]) //找到一种路径,记录到res中,注意必须是path[:]而不是path
- return
- if (not root.left) and (not root.right):return // 遇到叶子节点直接返回
- if root.left: //左
- targetSum -= root.left.val
- path.append(root.left.val) //递归前记录节点
- pathes(root.left,targetSum) //递归
- targetSum += root.left.val //回溯
- path.pop() //回溯
- if root.right: //右
- targetSum -= root.right.val
- path.append(root.right.val) //递归前记录节点
- pathes(root.right,targetSum) //递归
- targetSum += root.right.val //回溯
- path.pop() //回溯
- return
-
- if root == None:return [] //处理空TreeNode
- else:
- path.append(root.val) //首先处理根节点
- pathes(root,targetSum-root.val)
- return res
+class solution:
+ def pathsum(self, root: treenode, targetsum: int) -> list[list[int]]:
+
+ def traversal(cur_node, remain):
+ if not cur_node.left and not cur_node.right and remain == 0:
+ result.append(path[:])
+ return
+
+ if not cur_node.left and not cur_node.right: return
+
+ if cur_node.left:
+ path.append(cur_node.left.val)
+ remain -= cur_node.left.val
+ traversal(cur_node.left, remain)
+ path.pop()
+ remain += cur_node.left.val
+
+ if cur_node.right:
+ path.append(cur_node.right.val)
+ remain -= cur_node.right.val
+ traversal(cur_node.right, remain)
+ path.pop()
+ remain += cur_node.right.val
+
+ result, path = [], []
+ if not root:
+ return []
+ path.append(root.val)
+ traversal(root, targetsum - root.val)
+ return result
```
-Go:
+## go
-> 112. 路径总和
+112. 路径总和
```go
//递归法
/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
+ * definition for a binary tree node.
+ * type treenode struct {
+ * val int
+ * left *treenode
+ * right *treenode
* }
*/
-func hasPathSum(root *TreeNode, targetSum int) bool {
+func haspathsum(root *treenode, targetsum int) bool {
var flage bool //找没找到的标志
if root==nil{
return flage
}
- pathSum(root,0,targetSum,&flage)
+ pathsum(root,0,targetsum,&flage)
return flage
}
-func pathSum(root *TreeNode, sum int,targetSum int,flage *bool){
- sum+=root.Val
- if root.Left==nil&&root.Right==nil&&sum==targetSum{
+func pathsum(root *treenode, sum int,targetsum int,flage *bool){
+ sum+=root.val
+ if root.left==nil&&root.right==nil&&sum==targetsum{
*flage=true
return
}
- if root.Left!=nil&&!(*flage){//左节点不为空且还没找到
- pathSum(root.Left,sum,targetSum,flage)
+ if root.left!=nil&&!(*flage){//左节点不为空且还没找到
+ pathsum(root.left,sum,targetsum,flage)
}
- if root.Right!=nil&&!(*flage){//右节点不为空且没找到
- pathSum(root.Right,sum,targetSum,flage)
+ if root.right!=nil&&!(*flage){//右节点不为空且没找到
+ pathsum(root.right,sum,targetsum,flage)
}
}
```
-
-
-> 113 递归法
+113 递归法
```go
/**
- * Definition for a binary tree node.
- * type TreeNode struct {
- * Val int
- * Left *TreeNode
- * Right *TreeNode
+ * definition for a binary tree node.
+ * type treenode struct {
+ * val int
+ * left *treenode
+ * right *treenode
* }
*/
-func pathSum(root *TreeNode, targetSum int) [][]int {
+func pathsum(root *treenode, targetsum int) [][]int {
var result [][]int//最终结果
if root==nil{
return result
}
- var sumNodes []int//经过路径的节点集合
- hasPathSum(root,&sumNodes,targetSum,&result)
+ var sumnodes []int//经过路径的节点集合
+ haspathsum(root,&sumnodes,targetsum,&result)
return result
}
-func hasPathSum(root *TreeNode,sumNodes *[]int,targetSum int,result *[][]int){
- *sumNodes=append(*sumNodes,root.Val)
- if root.Left==nil&&root.Right==nil{//叶子节点
- fmt.Println(*sumNodes)
+func haspathsum(root *treenode,sumnodes *[]int,targetsum int,result *[][]int){
+ *sumnodes=append(*sumnodes,root.val)
+ if root.left==nil&&root.right==nil{//叶子节点
+ fmt.println(*sumnodes)
var sum int
var number int
- for k,v:=range *sumNodes{//求该路径节点的和
+ for k,v:=range *sumnodes{//求该路径节点的和
sum+=v
number=k
}
- tempNodes:=make([]int,number+1)//新的nodes接受指针里的值,防止最终指针里的值发生变动,导致最后的结果都是最后一个sumNodes的值
- for k,v:=range *sumNodes{
- tempNodes[k]=v
+ tempnodes:=make([]int,number+1)//新的nodes接受指针里的值,防止最终指针里的值发生变动,导致最后的结果都是最后一个sumnodes的值
+ for k,v:=range *sumnodes{
+ tempnodes[k]=v
}
- if sum==targetSum{
- *result=append(*result,tempNodes)
+ if sum==targetsum{
+ *result=append(*result,tempnodes)
}
}
- if root.Left!=nil{
- hasPathSum(root.Left,sumNodes,targetSum,result)
- *sumNodes=(*sumNodes)[:len(*sumNodes)-1]//回溯
+ if root.left!=nil{
+ haspathsum(root.left,sumnodes,targetsum,result)
+ *sumnodes=(*sumnodes)[:len(*sumnodes)-1]//回溯
}
- if root.Right!=nil{
- hasPathSum(root.Right,sumNodes,targetSum,result)
- *sumNodes=(*sumNodes)[:len(*sumNodes)-1]//回溯
+ if root.right!=nil{
+ haspathsum(root.right,sumnodes,targetsum,result)
+ *sumnodes=(*sumnodes)[:len(*sumnodes)-1]//回溯
}
}
```
-JavaScript:
+## javascript
0112.路径总和
```javascript
/**
- * @param {TreeNode} root
- * @param {number} targetSum
+ * @param {treenode} root
+ * @param {number} targetsum
* @return {boolean}
*/
-let hasPathSum = function (root, targetSum) {
+let haspathsum = function (root, targetsum) {
// 递归法
const traversal = (node, cnt) => {
// 遇到叶子节点,并且计数为0
@@ -597,19 +612,19 @@ let hasPathSum = function (root, targetSum) {
return false;
};
if (!root) return false;
- return traversal(root, targetSum - root.val);
+ return traversal(root, targetsum - root.val);
// 精简代码:
// if (!root) return false;
- // if (!root.left && !root.right && targetSum === root.val) return true;
- // return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
+ // if (!root.left && !root.right && targetsum === root.val) return true;
+ // return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
};
```
0113.路径总和-ii
```javascript
-let pathSum = function (root, targetSum) {
+let pathsum = function (root, targetsum) {
// 递归法
// 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
const res = [];
@@ -635,62 +650,29 @@ let pathSum = function (root, targetSum) {
return;
};
if (!root) return res;
- travelsal(root, targetSum - root.val, [root.val]); // 把根节点放进路径
+ travelsal(root, targetsum - root.val, [root.val]); // 把根节点放进路径
return res;
};
```
-
-0112 路径总和
+113 路径总和 精简版
```javascript
-var hasPathSum = function(root, targetSum) {
+var pathsum = function(root, targetsum) {
//递归方法
- // 1. 确定函数参数
- const traversal = function(node,count){
- // 2. 确定终止条件
- if(node.left===null&&node.right===null&&count===0){
- return true;
- }
- if(node.left===null&&node.right===null){
- return false;
- }
- //3. 单层递归逻辑
- if(node.left){
- if(traversal(node.left,count-node.left.val)){
- return true;
- }
- }
- if(node.right){
- if(traversal(node.right,count-node.right.val)){
- return true;
- }
- }
- return false;
- }
- if(root===null){
- return false;
- }
- return traversal(root,targetSum-root.val);
-};
-```
-113 路径总和
-```javascript
-var pathSum = function(root, targetSum) {
- //递归方法
- let resPath = [],curPath = [];
+ let respath = [],curpath = [];
// 1. 确定递归函数参数
- const travelTree = function(node,count){
- curPath.push(node.val);
+ const traveltree = function(node,count){
+ curpath.push(node.val);
count-=node.val;
if(node.left===null&&node.right===null&&count===0){
- resPath.push([...curPath]);
+ respath.push([...curpath]);
}
- node.left&&travelTree(node.left,count);
- node.right&&travelTree(node.right,count);
- let cur = curPath.pop();
+ node.left&&traveltree(node.left,count);
+ node.right&&traveltree(node.right,count);
+ let cur = curpath.pop();
count-=cur;
}
if(root===null){
- return resPath;
+ return respath;
}
travelTree(root,targetSum);
return resPath;
@@ -699,8 +681,9 @@ var pathSum = function(root, targetSum) {
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0115.不同的子序列.md b/problems/0115.不同的子序列.md
index 014eb3cd..e964e95d 100644
--- a/problems/0115.不同的子序列.md
+++ b/problems/0115.不同的子序列.md
@@ -82,7 +82,7 @@ dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串
初始化分析完毕,代码如下:
-```C++
+```CPP
vector> dp(s.size() + 1, vector(t.size() + 1));
for (int i = 0; i <= s.size(); i++) dp[i][0] = 1;
for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 其实这行代码可以和dp数组初始化的时候放在一起,但我为了凸显初始化的逻辑,所以还是加上了。
@@ -97,7 +97,7 @@ for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 其实这行代码可以和
代码如下:
-```C++
+```CPP
for (int i = 1; i <= s.size(); i++) {
for (int j = 1; j <= t.size(); j++) {
if (s[i - 1] == t[j - 1]) {
@@ -120,7 +120,7 @@ for (int i = 1; i <= s.size(); i++) {
动规五部曲分析完毕,代码如下:
-```C++
+```CPP
class Solution {
public:
int numDistinct(string s, string t) {
@@ -250,4 +250,4 @@ const numDistinct = (s, t) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0116.填充每个节点的下一个右侧节点指针.md b/problems/0116.填充每个节点的下一个右侧节点指针.md
index 28e6f645..34c666f3 100644
--- a/problems/0116.填充每个节点的下一个右侧节点指针.md
+++ b/problems/0116.填充每个节点的下一个右侧节点指针.md
@@ -52,7 +52,7 @@ struct Node {
图中cur节点为元素4,那么搭线的逻辑代码:(**注意注释中操作1和操作2和图中的对应关系**)
-```C++
+```CPP
if (cur->left) cur->left->next = cur->right; // 操作1
if (cur->right) {
if (cur->next) cur->right->next = cur->next->left; // 操作2
@@ -63,7 +63,7 @@ if (cur->right) {
理解到这里,使用前序遍历,那么不难写出如下代码:
-```C++
+```CPP
class Solution {
private:
void traversal(Node* cur) {
@@ -93,7 +93,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
Node* connect(Node* root) {
@@ -130,26 +130,134 @@ public:
## Java
```java
+// 递归法
+class Solution {
+ public void traversal(Node cur) {
+ if (cur == null) return;
+ if (cur.left != null) cur.left.next = cur.right; // 操作1
+ if (cur.right != null) {
+ if(cur.next != null) cur.right.next = cur.next.left; //操作2
+ else cur.right.next = null;
+ }
+ traversal(cur.left); // 左
+ traversal(cur.right); //右
+ }
+ public Node connect(Node root) {
+ traversal(root);
+ return root;
+ }
+}
+```
+```java
+// 迭代法
+class Solution {
+ public Node connect(Node root) {
+ if (root == null) return root;
+ Queue que = new LinkedList();
+ que.offer(root);
+ Node nodePre = null;
+ Node node = null;
+ while (!que.isEmpty()) {
+ int size = que.size();
+ for (int i=0; i 'Node':
+ def traversal(cur: 'Node') -> 'Node':
+ if not cur: return []
+ if cur.left: cur.left.next = cur.right # 操作1
+ if cur.right:
+ if cur.next:
+ cur.right.next = cur.next.left # 操作2
+ else:
+ cur.right.next = None
+ traversal(cur.left) # 左
+ traversal(cur.right) # 右
+ traversal(root)
+ return root
+```
+```python
+# 迭代法
+class Solution:
+ def connect(self, root: 'Node') -> 'Node':
+ if not root: return
+ res = []
+ queue = [root]
+ while queue:
+ size = len(queue)
+ for i in range(size): # 开始每一层的遍历
+ if i==0:
+ nodePre = queue.pop(0) # 记录一层的头结点
+ node = nodePre
+ else:
+ node = queue.pop(0)
+ nodePre.next = node # 本层前一个节点next指向本节点
+ nodePre = nodePre.next
+ if node.left: queue.append(node.left)
+ if node.right: queue.append(node.right)
+ nodePre.next = None # 本层最后一个节点指向None
+ return root
```
-
## Go
```go
+
```
## JavaScript
```js
+const connect = root => {
+ if (!root) return root;
+ // 根节点入队
+ const Q = [root];
+ while (Q.length) {
+ const len = Q.length;
+ // 遍历这一层的所有节点
+ for (let i = 0; i < len; i++) {
+ // 队头出队
+ const node = Q.shift();
+ // 连接
+ if (i < len - 1) {
+ // 新的队头是node的右边元素
+ node.next = Q[0];
+ }
+ // 队头左节点有值,放入队列
+ node.left && Q.push(node.left);
+ // 队头右节点有值,放入队列
+ node.right && Q.push(node.right);
+ }
+ }
+ return root;
+};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0121.买卖股票的最佳时机.md b/problems/0121.买卖股票的最佳时机.md
index 259fff34..6d068c22 100644
--- a/problems/0121.买卖股票的最佳时机.md
+++ b/problems/0121.买卖股票的最佳时机.md
@@ -33,7 +33,7 @@
这道题目最直观的想法,就是暴力,找最优间距了。
-```C++
+```CPP
class Solution {
public:
int maxProfit(vector& prices) {
@@ -59,7 +59,7 @@ public:
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int maxProfit(vector& prices) {
@@ -139,7 +139,7 @@ dp[5][1]就是最终结果。
以上分析完毕,C++代码如下:
-```C++
+```CPP
// 版本一
class Solution {
public:
@@ -169,7 +169,7 @@ dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
那么我们只需要记录 当前天的dp状态和前一天的dp状态就可以了,可以使用滚动数组来节省空间,代码如下:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -313,6 +313,26 @@ func max(a,b int)int {
}
```
+JavaScript:
+
+```javascript
+const maxProfit = prices => {
+ const len = prices.length;
+ // 创建dp数组
+ const dp = new Array(len).fill([0, 0]);
+ // dp数组初始化
+ dp[0] = [-prices[0], 0];
+ for (let i = 1; i < len; i++) {
+ // 更新dp[i]
+ dp[i] = [
+ Math.max(dp[i - 1][0], -prices[i]),
+ Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0]),
+ ];
+ }
+ return dp[len - 1][1];
+};
+```
+
@@ -320,4 +340,4 @@ func max(a,b int)int {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md
index 60d4591f..53737532 100644
--- a/problems/0122.买卖股票的最佳时机II.md
+++ b/problems/0122.买卖股票的最佳时机II.md
@@ -80,7 +80,7 @@
对应C++代码如下:
-```C++
+```CPP
class Solution {
public:
int maxProfit(vector& prices) {
@@ -99,7 +99,7 @@ public:
动态规划将在下一个系列详细讲解,本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
-```C++
+```CPP
class Solution {
public:
int maxProfit(vector& prices) {
@@ -239,4 +239,4 @@ var maxProfit = function(prices) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0122.买卖股票的最佳时机II(动态规划).md b/problems/0122.买卖股票的最佳时机II(动态规划).md
index 8ed70063..7492ee04 100644
--- a/problems/0122.买卖股票的最佳时机II(动态规划).md
+++ b/problems/0122.买卖股票的最佳时机II(动态规划).md
@@ -74,7 +74,7 @@
代码如下:(注意代码中的注释,标记了和121.买卖股票的最佳时机唯一不同的地方)
-```C++
+```CPP
class Solution {
public:
int maxProfit(vector& prices) {
@@ -106,7 +106,7 @@ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
这里我依然给出滚动数组的版本,C++代码如下:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -231,4 +231,4 @@ const maxProfit = (prices) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md
index 7ff1bfe2..0c92a5a2 100644
--- a/problems/0123.买卖股票的最佳时机III.md
+++ b/problems/0123.买卖股票的最佳时机III.md
@@ -127,7 +127,7 @@ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
以上五部都分析完了,不难写出如下代码:
-```C++
+```CPP
// 版本一
class Solution {
public:
@@ -153,7 +153,7 @@ public:
当然,大家可以看到力扣官方题解里的一种优化空间写法,我这里给出对应的C++版本:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -278,7 +278,44 @@ class Solution:
return dp[4]
```
-Go:
+JavaScript:
+
+> 版本一:
+
+```javascript
+const maxProfit = prices => {
+ const len = prices.length;
+ const dp = new Array(len).fill(0).map(x => new Array(5).fill(0));
+ dp[0][1] = -prices[0];
+ dp[0][3] = -prices[0];
+ for (let i = 1; i < len; i++) {
+ dp[i][0] = dp[i - 1][0];
+ dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
+ dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
+ dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
+ dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
+ }
+ return dp[len - 1][4];
+};
+```
+
+> 版本二:
+
+```javascript
+const maxProfit = prices => {
+ const len = prices.length;
+ const dp = new Array(5).fill(0);
+ dp[1] = -prices[0];
+ dp[3] = -prices[0];
+ for (let i = 1; i < len; i++) {
+ dp[1] = Math.max(dp[1], dp[0] - prices[i]);
+ dp[2] = Math.max(dp[2], dp[1] + prices[i]);
+ dp[3] = Math.max(dp[3], dp[2] - prices[i]);
+ dp[4] = Math.max(dp[4], dp[3] + prices[i]);
+ }
+ return dp[4];
+};
+```
@@ -287,4 +324,4 @@ Go:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0129.求根到叶子节点数字之和.md b/problems/0129.求根到叶子节点数字之和.md
index f8c93382..17642793 100644
--- a/problems/0129.求根到叶子节点数字之和.md
+++ b/problems/0129.求根到叶子节点数字之和.md
@@ -52,7 +52,7 @@ if (!cur->left && !cur->right) { // 遇到了叶子节点
这里vectorToInt函数就是把数组转成int,代码如下:
-```C++
+```CPP
int vectorToInt(const vector& vec) {
int sum = 0;
for (int i = 0; i < vec.size(); i++) {
@@ -78,7 +78,7 @@ int vectorToInt(const vector& vec) {
代码如下:
-```C++
+```CPP
// 中
if (cur->left) { // 左 (空节点不遍历)
path.push_back(cur->left->val);
@@ -94,7 +94,7 @@ if (cur->right) { // 右 (空节点不遍历)
这里要注意回溯和递归要永远在一起,一个递归,对应一个回溯,是一对一的关系,有的同学写成如下代码:
-```C++
+```CPP
if (cur->left) { // 左 (空节点不遍历)
path.push_back(cur->left->val);
traversal(cur->left); // 递归
@@ -111,7 +111,7 @@ path.pop_back(); // 回溯
关键逻辑分析完了,整体C++代码如下:
-```C++
+```CPP
class Solution {
private:
int result;
@@ -165,7 +165,32 @@ public:
Java:
Python:
+```python3
+class Solution:
+ def sumNumbers(self, root: TreeNode) -> int:
+ res = 0
+ path = []
+ def backtrace(root):
+ nonlocal res
+ if not root: return # 节点空则返回
+ path.append(root.val)
+ if not root.left and not root.right: # 遇到了叶子节点
+ res += get_sum(path)
+ if root.left: # 左子树不空
+ backtrace(root.left)
+ if root.right: # 右子树不空
+ backtrace(root.right)
+ path.pop()
+ def get_sum(arr):
+ s = 0
+ for i in range(len(arr)):
+ s = s * 10 + arr[i]
+ return s
+
+ backtrace(root)
+ return res
+```
Go:
JavaScript:
@@ -176,4 +201,4 @@ JavaScript:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md
index 43453409..6fe2758b 100644
--- a/problems/0131.分割回文串.md
+++ b/problems/0131.分割回文串.md
@@ -70,7 +70,7 @@
代码如下:
-```C++
+```CPP
vector> result;
vector path; // 放已经回文的子串
void backtracking (const string& s, int startIndex) {
@@ -88,7 +88,7 @@ void backtracking (const string& s, int startIndex) {
所以终止条件代码如下:
-```C++
+```CPP
void backtracking (const string& s, int startIndex) {
// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
if (startIndex >= s.size()) {
@@ -108,7 +108,7 @@ void backtracking (const string& s, int startIndex) {
代码如下:
-```C++
+```CPP
for (int i = startIndex; i < s.size(); i++) {
if (isPalindrome(s, startIndex, i)) { // 是回文子串
// 获取[startIndex,i]在s中的子串
@@ -132,7 +132,7 @@ for (int i = startIndex; i < s.size(); i++) {
那么判断回文的C++代码如下:
-```C++
+```CPP
bool isPalindrome(const string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
if (s[i] != s[j]) {
@@ -151,7 +151,7 @@ for (int i = startIndex; i < s.size(); i++) {
根据Carl给出的回溯算法模板:
-```C++
+```CPP
void backtracking(参数) {
if (终止条件) {
存放结果;
@@ -169,7 +169,7 @@ void backtracking(参数) {
不难写出如下代码:
-```C++
+```CPP
class Solution {
private:
vector> result;
@@ -395,4 +395,4 @@ var partition = function(s) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0132.分割回文串II.md b/problems/0132.分割回文串II.md
index 856262d6..80784301 100644
--- a/problems/0132.分割回文串II.md
+++ b/problems/0132.分割回文串II.md
@@ -101,7 +101,7 @@ dp[i]: 范围是[0, i]的回文子串,最少分割次数是dp[i]。
代码如下:
-```C++
+```CPP
vector dp(s.size(), INT_MAX);
dp[0] = 0;
```
@@ -109,7 +109,7 @@ dp[0] = 0;
其实也可以这样初始化,更具dp[i]的定义,dp[i]的最大值其实就是i,也就是把每个字符分割出来。
所以初始化代码也可以为:
-```C++
+```CPP
vector dp(s.size());
for (int i = 0; i < s.size(); i++) dp[i] = i;
```
@@ -122,7 +122,7 @@ j是在[0,i]之间,所以遍历i的for循环一定在外层,这里遍历j
代码如下:
-```C++
+```CPP
for (int i = 1; i < s.size(); i++) {
if (isPalindromic[0][i]) { // 判断是不是回文子串
dp[i] = 0;
@@ -149,7 +149,7 @@ for (int i = 1; i < s.size(); i++) {
代码如下:
-```C++
+```CPP
vector> isPalindromic(s.size(), vector(s.size(), false));
for (int i = s.size() - 1; i >= 0; i--) {
for (int j = i; j < s.size(); j++) {
@@ -168,7 +168,7 @@ for (int i = s.size() - 1; i >= 0; i--) {
以上分析完毕,代码如下:
-```C++
+```CPP
class Solution {
public:
int minCut(string s) {
@@ -252,5 +252,5 @@ class Solution:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md
index 9b660ea0..e270c059 100644
--- a/problems/0134.加油站.md
+++ b/problems/0134.加油站.md
@@ -65,7 +65,7 @@ cost = [3,4,3]
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int canCompleteCircuit(vector& gas, vector& cost) {
@@ -99,7 +99,7 @@ C++暴力解法在leetcode上提交也可以过。
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int canCompleteCircuit(vector& gas, vector& cost) {
@@ -160,7 +160,7 @@ i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int canCompleteCircuit(vector& gas, vector& cost) {
@@ -288,4 +288,4 @@ var canCompleteCircuit = function(gas, cost) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0135.分发糖果.md b/problems/0135.分发糖果.md
index 2d3fca84..3865e14b 100644
--- a/problems/0135.分发糖果.md
+++ b/problems/0135.分发糖果.md
@@ -47,7 +47,7 @@
代码如下:
-```C++
+```CPP
// 从前向后
for (int i = 1; i < ratings.size(); i++) {
if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
@@ -80,7 +80,7 @@ for (int i = 1; i < ratings.size(); i++) {
所以该过程代码如下:
-```C++
+```CPP
// 从后向前
for (int i = ratings.size() - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1] ) {
@@ -90,7 +90,7 @@ for (int i = ratings.size() - 2; i >= 0; i--) {
```
整体代码如下:
-```C++
+```CPP
class Solution {
public:
int candy(vector& ratings) {
@@ -242,4 +242,4 @@ var candy = function(ratings) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md
index 4ba08aa9..0c19a614 100644
--- a/problems/0139.单词拆分.md
+++ b/problems/0139.单词拆分.md
@@ -45,7 +45,7 @@
那么这里我也给出回溯法C++代码:
-```C++
+```CPP
class Solution {
private:
bool backtracking (const string& s, const unordered_set& wordSet, int startIndex) {
@@ -86,7 +86,7 @@ public:
C++代码如下:
-```C++
+```CPP
class Solution {
private:
bool backtracking (const string& s,
@@ -190,7 +190,7 @@ dp[s.size()]就是最终结果。
动规五部曲分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
bool wordBreak(string s, vector& wordDict) {
@@ -319,4 +319,4 @@ const wordBreak = (s, wordDict) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0141.环形链表.md b/problems/0141.环形链表.md
index 4a40f953..78bcfd43 100644
--- a/problems/0141.环形链表.md
+++ b/problems/0141.环形链表.md
@@ -14,7 +14,7 @@
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
-
+

# 思路
@@ -45,7 +45,7 @@ fast和slow各自再走一步, fast和slow就相遇了
C++代码如下
-```C++
+```CPP
class Solution {
public:
bool hasCycle(ListNode *head) {
@@ -74,6 +74,21 @@ public:
## Java
```java
+public class Solution {
+ public boolean hasCycle(ListNode head) {
+ ListNode fast = head;
+ ListNode slow = head;
+ // 空链表、单节点链表一定不会有环
+ while (fast != null && fast.next != null) {
+ fast = fast.next.next; // 快指针,一次移动两步
+ slow = slow.next; // 慢指针,一次移动一步
+ if (fast == slow) { // 快慢指针相遇,表明有环
+ return true;
+ }
+ }
+ return false; // 正常走到链表末尾,表明没有环
+ }
+}
```
## Python
@@ -105,5 +120,5 @@ class Solution:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0142.环形链表II.md b/problems/0142.环形链表II.md
index 9deb1e0c..91e14e27 100644
--- a/problems/0142.环形链表II.md
+++ b/problems/0142.环形链表II.md
@@ -109,7 +109,7 @@ fast指针走过的节点数:` x + y + n (y + z)`,n为fast指针在环内走
代码如下:
-```C++
+```CPP
/**
* Definition for singly-linked list.
* struct ListNode {
@@ -301,4 +301,4 @@ var detectCycle = function(head) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0143.重排链表.md b/problems/0143.重排链表.md
index c4e8d8f7..76df63b7 100644
--- a/problems/0143.重排链表.md
+++ b/problems/0143.重排链表.md
@@ -1,4 +1,3 @@
-
@@ -25,7 +24,7 @@
代码如下:
-```C++
+```CPP
class Solution {
public:
void reorderList(ListNode* head) {
@@ -63,7 +62,8 @@ public:
## 方法二
把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。这种方法比操作数组容易一些,不用双指针模拟一前一后了
-```C++
+
+```CPP
class Solution {
public:
void reorderList(ListNode* head) {
@@ -108,7 +108,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
private:
// 反转链表
@@ -176,15 +176,116 @@ public:
Java:
-Python:
+```java
+public class ReorderList {
+ public void reorderList(ListNode head) {
+ ListNode fast = head, slow = head;
+ //求出中点
+ while (fast.next != null && fast.next.next != null) {
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+ //right就是右半部分 12345 就是45 1234 就是34
+ ListNode right = slow.next;
+ //断开左部分和右部分
+ slow.next = null;
+ //反转右部分 right就是反转后右部分的起点
+ right = reverseList(right);
+ //左部分的起点
+ ListNode left = head;
+ //进行左右部分来回连接
+ //这里左部分的节点个数一定大于等于右部分的节点个数 因此只判断right即可
+ while (right != null) {
+ ListNode curLeft = left.next;
+ left.next = right;
+ left = curLeft;
+ ListNode curRight = right.next;
+ right.next = left;
+ right = curRight;
+ }
+ }
+
+ public ListNode reverseList(ListNode head) {
+ ListNode headNode = new ListNode(0);
+ ListNode cur = head;
+ ListNode next = null;
+ while (cur != null) {
+ next = cur.next;
+ cur.next = headNode.next;
+ headNode.next = cur;
+ cur = next;
+ }
+ return headNode.next;
+ }
+}
+```
+
+Python:
+```python3
+# 方法二 双向队列
+class Solution:
+ def reorderList(self, head: ListNode) -> None:
+ """
+ Do not return anything, modify head in-place instead.
+ """
+ d = collections.deque()
+ tmp = head
+ while tmp.next: # 链表除了首元素全部加入双向队列
+ d.append(tmp.next)
+ tmp = tmp.next
+ tmp = head
+ while len(d): # 一后一前加入链表
+ tmp.next = d.pop()
+ tmp = tmp.next
+ if len(d):
+ tmp.next = d.popleft()
+ tmp = tmp.next
+ tmp.next = None # 尾部置空
+
+# 方法三 反转链表
+class Solution:
+ def reorderList(self, head: ListNode) -> None:
+ if head == None or head.next == None:
+ return True
+ slow, fast = head, head
+ while fast and fast.next:
+ slow = slow.next
+ fast = fast.next.next
+ right = slow.next # 分割右半边
+ slow.next = None # 切断
+ right = self.reverseList(right) #反转右半边
+ left = head
+ # 左半边一定比右半边长, 因此判断右半边即可
+ while right:
+ curLeft = left.next
+ left.next = right
+ left = curLeft
+
+ curRight = right.next
+ right.next = left
+ right = curRight
+
+
+ def reverseList(self, head: ListNode) -> ListNode:
+ cur = head
+ pre = None
+ while(cur!=None):
+ temp = cur.next # 保存一下cur的下一个节点
+ cur.next = pre # 反转
+ pre = cur
+ cur = temp
+ return pre
+```
Go:
JavaScript:
-----------------------
+
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
+
diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md
index aceb91b4..2b294337 100644
--- a/problems/0150.逆波兰表达式求值.md
+++ b/problems/0150.逆波兰表达式求值.md
@@ -80,7 +80,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int evalRPN(vector& tokens) {
@@ -241,4 +241,4 @@ def evalRPN(tokens) -> int:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md
index 32d9deef..3f4d00b2 100644
--- a/problems/0151.翻转字符串里的单词.md
+++ b/problems/0151.翻转字符串里的单词.md
@@ -61,7 +61,7 @@ https://leetcode-cn.com/problems/reverse-words-in-a-string/
思路很明确了,我们说一说代码的实现细节,就拿移除多余空格来说,一些同学会上来写如下代码:
-```C++
+```CPP
void removeExtraSpaces(string& s) {
for (int i = s.size() - 1; i > 0; i--) {
if (s[i] == s[i - 1] && s[i] == ' ') {
@@ -93,7 +93,7 @@ erase操作上面还套了一个for循环,那么以上代码移除冗余空格
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
-```C++
+```CPP
void removeExtraSpaces(string& s) {
int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
// 去掉字符串前面的空格
@@ -141,7 +141,7 @@ void reverse(string& s, int start, int end) {
本题C++整体代码
-```C++
+```CPP
// 版本一
class Solution {
public:
@@ -474,4 +474,4 @@ function reverse(strArr, start, end) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0160.相交链表.md b/problems/0160.相交链表.md
index d26f66fd..7ac1848b 100644
--- a/problems/0160.相交链表.md
+++ b/problems/0160.相交链表.md
@@ -1,2 +1,3 @@
同:[链表:链表相交](./面试题02.07.链表相交.md)
+
diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md
index 46c6f7f0..9fe7a919 100644
--- a/problems/0188.买卖股票的最佳时机IV.md
+++ b/problems/0188.买卖股票的最佳时机IV.md
@@ -84,7 +84,7 @@ vector> dp(prices.size(), vector(2 * k + 1, 0));
同理可以类比剩下的状态,代码如下:
-```C++
+```CPP
for (int j = 0; j < 2 * k - 1; j += 2) {
dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
@@ -117,7 +117,7 @@ for (int j = 0; j < 2 * k - 1; j += 2) {
代码如下:
-```C++
+```CPP
for (int j = 1; j < 2 * k; j += 2) {
dp[0][j] = -prices[0];
}
@@ -139,7 +139,7 @@ for (int j = 1; j < 2 * k; j += 2) {
以上分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int maxProfit(int k, vector& prices) {
@@ -287,4 +287,4 @@ const maxProfit = (k,prices) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0189.旋转数组.md b/problems/0189.旋转数组.md
index 9f565c1d..be46bf4c 100644
--- a/problems/0189.旋转数组.md
+++ b/problems/0189.旋转数组.md
@@ -69,7 +69,7 @@
C++代码如下:
-```C++
+```CPP
class Solution {
public:
void rotate(vector& nums, int k) {
@@ -137,6 +137,6 @@ class Solution:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0198.打家劫舍.md b/problems/0198.打家劫舍.md
index 63a68c36..93b56dae 100644
--- a/problems/0198.打家劫舍.md
+++ b/problems/0198.打家劫舍.md
@@ -25,7 +25,7 @@
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
-
+
提示:
@@ -59,7 +59,7 @@
代码如下:
-```C++
+```CPP
vector dp(nums.size());
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
@@ -70,7 +70,7 @@ dp[1] = max(nums[0], nums[1]);
dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!
代码如下:
-```C++
+```CPP
for (int i = 2; i < nums.size(); i++) {
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
}
@@ -86,7 +86,7 @@ for (int i = 2; i < nums.size(); i++) {
以上分析完毕,C++代码如下:
-```C++
+```CPP
class Solution {
public:
int rob(vector& nums) {
@@ -175,6 +175,22 @@ func max(a, b int) int {
}
```
+JavaScript:
+
+```javascript
+const rob = nums => {
+ // 数组长度
+ const len = nums.length;
+ // dp数组初始化
+ const dp = [nums[0], Math.max(nums[0], nums[1])];
+ // 从下标2开始遍历
+ for (let i = 2; i < len; i++) {
+ dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
+ }
+ return dp[len - 1];
+};
+```
+
@@ -182,4 +198,4 @@ func max(a, b int) int {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md
index d1bccd64..2e784e6a 100644
--- a/problems/0202.快乐数.md
+++ b/problems/0202.快乐数.md
@@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/happy-number/
C++代码如下:
-```C++
+```CPP
class Solution {
public:
// 取数值各个位上的单数之和
@@ -111,25 +111,29 @@ Python:
```python
class Solution:
def isHappy(self, n: int) -> bool:
- set_ = set()
- while 1:
- sum_ = self.getSum(n)
- if sum_ == 1:
+ def calculate_happy(num):
+ sum_ = 0
+
+ # 从个位开始依次取,平方求和
+ while num:
+ sum_ += (num % 10) ** 2
+ num = num // 10
+ return sum_
+
+ # 记录中间结果
+ record = set()
+
+ while True:
+ n = calculate_happy(n)
+ if n == 1:
return True
- #如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
- if sum_ in set_:
+
+ # 如果中间结果重复出现,说明陷入死循环了,该数不是快乐数
+ if n in record:
return False
else:
- set_.add(sum_)
- n = sum_
-
- #取数值各个位上的单数之和
- def getSum(self, n):
- sum_ = 0
- while n > 0:
- sum_ += (n%10) * (n%10)
- n //= 10
- return sum_
+ record.add(n)
+
```
Go:
@@ -193,4 +197,4 @@ var isHappy = function(n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md
index cac9f233..9235d47e 100644
--- a/problems/0203.移除链表元素.md
+++ b/problems/0203.移除链表元素.md
@@ -89,7 +89,7 @@ https://leetcode-cn.com/problems/remove-linked-list-elements/
**直接使用原来的链表来进行移除节点操作:**
-```C++
+```CPP
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
@@ -118,7 +118,7 @@ public:
**设置一个虚拟头结点在进行移除节点操作:**
-```C++
+```CPP
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
@@ -146,8 +146,39 @@ public:
## 其他语言版本
+C:
+```c
+/**
+ * Definition for singly-linked list.
+ * struct ListNode {
+ * int val;
+ * struct ListNode *next;
+ * };
+ */
+struct ListNode* removeElements(struct ListNode* head, int val){
+ typedef struct ListNode ListNode;
+ ListNode *shead;
+ shead = (ListNode *)malloc(sizeof(ListNode));
+ shead->next = head;
+ ListNode *cur = shead;
+ while(cur->next != NULL){
+ if (cur->next->val == val){
+ ListNode *tmp = cur->next;
+ cur->next = cur->next->next;
+ free(tmp);
+ }
+ else{
+ cur = cur->next;
+ }
+ }
+ head = shead->next;
+ free(shead);
+ return head;
+}
+```
+
Java:
```java
/**
@@ -273,6 +304,34 @@ var removeElements = function(head, val) {
};
```
+Swift:
+
+```swift
+/**
+ * Definition for singly-linked list.
+ * public class ListNode {
+ * public var val: Int
+ * public var next: ListNode?
+ * public init() { self.val = 0; self.next = nil; }
+ * public init(_ val: Int) { self.val = val; self.next = nil; }
+ * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
+ * }
+ */
+func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? {
+ let dummyNode = ListNode()
+ dummyNode.next = head
+ var currentNode = dummyNode
+ while let curNext = currentNode.next {
+ if curNext.val == val {
+ currentNode.next = curNext.next
+ } else {
+ currentNode = curNext
+ }
+ }
+ return dummyNode.next
+}
+```
+
@@ -280,4 +339,4 @@ var removeElements = function(head, val) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0205.同构字符串.md b/problems/0205.同构字符串.md
index 4e963ece..d5077e03 100644
--- a/problems/0205.同构字符串.md
+++ b/problems/0205.同构字符串.md
@@ -39,7 +39,7 @@
C++代码 如下:
-```C++
+```CPP
class Solution {
public:
bool isIsomorphic(string s, string t) {
@@ -68,6 +68,25 @@ public:
## Java
```java
+class Solution {
+ public boolean isIsomorphic(String s, String t) {
+ Map map1 = new HashMap<>();
+ Map map2 = new HashMap<>();
+ for (int i = 0, j = 0; i < s.length(); i++, j++) {
+ if (!map1.containsKey(s.charAt(i))) {
+ map1.put(s.charAt(i), t.charAt(j)); // map1保存 s[i] 到 t[j]的映射
+ }
+ if (!map2.containsKey(t.charAt(j))) {
+ map2.put(t.charAt(j), s.charAt(i)); // map2保存 t[j] 到 s[i]的映射
+ }
+ // 无法映射,返回 false
+ if (map1.get(s.charAt(i)) != t.charAt(j) || map2.get(t.charAt(j)) != s.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
```
## Python
@@ -89,5 +108,5 @@ public:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md
index 963d7916..8bb359bd 100644
--- a/problems/0206.翻转链表.md
+++ b/problems/0206.翻转链表.md
@@ -48,7 +48,7 @@ https://leetcode-cn.com/problems/reverse-linked-list/
# C++代码
## 双指针法
-```C++
+```CPP
class Solution {
public:
ListNode* reverseList(ListNode* head) {
@@ -74,7 +74,7 @@ public:
关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。
具体可以看代码(已经详细注释),**双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。**
-```C++
+```CPP
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
@@ -275,11 +275,67 @@ var reverseList = function(head) {
};
```
+Ruby:
+```ruby
+# 双指针
+# Definition for singly-linked list.
+# class ListNode
+# attr_accessor :val, :next
+# def initialize(val = 0, _next = nil)
+# @val = val
+# @next = _next
+# end
+# end
+def reverse_list(head)
+ # return nil if head.nil? # 循环判断条件亦能起到相同作用因此不必单独判断
+ cur, per = head, nil
+ until cur.nil?
+ tem = cur.next
+ cur.next = per
+ per = cur
+ cur = tem
+ end
+ per
+end
+# 递归
+# Definition for singly-linked list.
+# class ListNode
+# attr_accessor :val, :next
+# def initialize(val = 0, _next = nil)
+# @val = val
+# @next = _next
+# end
+# end
+def reverse_list(head)
+ reverse(nil, head)
+end
+
+def reverse(pre, cur)
+ return pre if cur.nil?
+ tem = cur.next
+ cur.next = pre
+ reverse(cur, tem) # 通过递归实现双指针法中的更新操作
+end
+```
+Kotlin:
+```Kotlin
+fun reverseList(head: ListNode?): ListNode? {
+ var pre: ListNode? = null
+ var cur = head
+ while (cur != null) {
+ val temp = cur.next
+ cur.next = pre
+ pre = cur
+ cur = temp
+ }
+ return pre
+}
+```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md
index 42687514..3219d16f 100644
--- a/problems/0209.长度最小的子数组.md
+++ b/problems/0209.长度最小的子数组.md
@@ -26,7 +26,7 @@
代码如下:
-```C++
+```CPP
class Solution {
public:
int minSubArrayLen(int s, vector& nums) {
@@ -86,7 +86,7 @@ public:
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int minSubArrayLen(int s, vector& nums) {
@@ -216,8 +216,31 @@ var minSubArrayLen = function(target, nums) {
};
```
+Swift:
+
+```swift
+func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int {
+ var result = Int.max
+ var sum = 0
+ var starIndex = 0
+ for endIndex in 0..= target {
+ result = min(result, endIndex - starIndex + 1)
+ sum -= nums[starIndex]
+ starIndex += 1
+ }
+ }
+
+ return result == Int.max ? 0 : result
+}
+```
+
+
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0213.打家劫舍II.md b/problems/0213.打家劫舍II.md
index 12951117..e828d17a 100644
--- a/problems/0213.打家劫舍II.md
+++ b/problems/0213.打家劫舍II.md
@@ -59,7 +59,7 @@
代码如下:
-```C++
+```CPP
// 注意注释中的情况二情况三,以及把198.打家劫舍的代码抽离出来了
class Solution {
public:
@@ -174,4 +174,4 @@ Go:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md
index 15220464..c9cfa973 100644
--- a/problems/0216.组合总和III.md
+++ b/problems/0216.组合总和III.md
@@ -94,7 +94,7 @@ void backtracking(int targetSum, int k, int sum, int startIndex)
所以 终止代码如下:
-```C++
+```CPP
if (path.size() == k) {
if (sum == targetSum) result.push_back(path);
return; // 如果path.size() == k 但sum != targetSum 直接返回
@@ -112,7 +112,7 @@ if (path.size() == k) {
代码如下:
-```C++
+```CPP
for (int i = startIndex; i <= 9; i++) {
sum += i;
path.push_back(i);
@@ -126,7 +126,7 @@ for (int i = startIndex; i <= 9; i++) {
参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
-```C++
+```CPP
class Solution {
private:
vector> result; // 存放结果集
@@ -398,4 +398,4 @@ var combinationSum3 = function(k, n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md
index ec68b6c6..0d3a818e 100644
--- a/problems/0222.完全二叉树的节点个数.md
+++ b/problems/0222.完全二叉树的节点个数.md
@@ -7,24 +7,23 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
-## 222.完全二叉树的节点个数
+# 222.完全二叉树的节点个数
题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/
给出一个完全二叉树,求出该树的节点个数。
-示例:
示例 1:
-输入:root = [1,2,3,4,5,6]
-输出:6
+* 输入:root = [1,2,3,4,5,6]
+* 输出:6
示例 2:
-输入:root = []
-输出:0
+* 输入:root = []
+* 输出:0
示例 3:
-输入:root = [1]
-输出:1
+* 输入:root = [1]
+* 输出:1
提示:
@@ -33,21 +32,22 @@
* 题目数据保证输入的树是 完全二叉树
-## 思路
+# 思路
本篇给出按照普通二叉树的求法以及利用完全二叉树性质的求法。
+
## 普通二叉树
首先按照普通二叉树的逻辑来求。
-这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
+这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
递归遍历的顺序依然是后序(左右中)。
### 递归
-如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)。
+如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)。
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
@@ -77,7 +77,7 @@ return treeNum;
所以整体C++代码如下:
-```C++
+```CPP
// 版本一
class Solution {
private:
@@ -96,7 +96,7 @@ public:
```
代码精简之后C++代码如下:
-```C++
+```CPP
// 版本二
class Solution {
public:
@@ -107,19 +107,19 @@ public:
};
```
-时间复杂度:O(n)
-空间复杂度:O(logn),算上了递归系统栈占用的空间
+* 时间复杂度:O(n)
+* 空间复杂度:O(logn),算上了递归系统栈占用的空间
**网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础**。
### 迭代法
-如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)。
+如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)。
那么只要模板少做改动,加一个变量result,统计节点数量就可以了
-```C++
+```CPP
class Solution {
public:
int countNodes(TreeNode* root) {
@@ -140,12 +140,12 @@ public:
}
};
```
-时间复杂度:O(n)
-空间复杂度:O(n)
+* 时间复杂度:O(n)
+* 空间复杂度:O(n)
## 完全二叉树
-以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A),这篇详细介绍了各种二叉树的特性。
+以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA),这篇详细介绍了各种二叉树的特性。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
@@ -163,7 +163,7 @@ public:
C++代码如下:
-```C++
+```CPP
class Solution {
public:
int countNodes(TreeNode* root) {
@@ -187,13 +187,12 @@ public:
};
```
-时间复杂度:O(logn * logn)
-空间复杂度:O(logn)
+* 时间复杂度:O(logn * logn)
+* 空间复杂度:O(logn)
-## 其他语言版本
+# 其他语言版本
-
-Java:
+## Java
```java
class Solution {
// 通用递归解法
@@ -238,9 +237,9 @@ class Solution {
}
```
-Python:
+## Python
-> 递归法:
+递归法:
```python
class Solution:
def countNodes(self, root: TreeNode) -> int:
@@ -255,7 +254,7 @@ class Solution:
return treeNum
```
-> 递归法:精简版
+递归法:精简版
```python
class Solution:
def countNodes(self, root: TreeNode) -> int:
@@ -264,7 +263,7 @@ class Solution:
return 1 + self.countNodes(root.left) + self.countNodes(root.right)
```
-> 迭代法:
+迭代法:
```python
import collections
class Solution:
@@ -285,7 +284,7 @@ class Solution:
return result
```
-> 完全二叉树
+完全二叉树
```python
class Solution:
def countNodes(self, root: TreeNode) -> int:
@@ -306,7 +305,7 @@ class Solution:
return self.countNodes(root.left) + self.countNodes(root.right) + 1
```
-Go:
+## Go
递归版本
@@ -361,7 +360,7 @@ func countNodes(root *TreeNode) int {
-JavaScript:
+## JavaScript:
递归版本
```javascript
@@ -436,4 +435,4 @@ var countNodes = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md
index b3e851a1..b327c17b 100644
--- a/problems/0225.用队列实现栈.md
+++ b/problems/0225.用队列实现栈.md
@@ -65,7 +65,7 @@ queue.empty();
详细如代码注释所示:
-```C++
+```CPP
class MyStack {
public:
queue que1;
@@ -118,7 +118,7 @@ public:
C++优化代码
-```C++
+```CPP
class MyStack {
public:
queue que;
@@ -460,4 +460,4 @@ MyStack.prototype.empty = function() {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md
index 44f0d3b4..6eb6f301 100644
--- a/problems/0226.翻转二叉树.md
+++ b/problems/0226.翻转二叉树.md
@@ -89,7 +89,7 @@ invertTree(root->right);
基于这递归三步法,代码基本写完,C++代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -111,7 +111,7 @@ public:
C++代码迭代法(前序遍历)
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -136,7 +136,7 @@ public:
C++代码如下迭代法(前序遍历)
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -168,7 +168,7 @@ public:
也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -196,7 +196,7 @@ public:
如果非要使用递归中序的方式写,也可以,如下代码就可以避免节点左右孩子翻转两次的情况:
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -215,7 +215,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
@@ -478,4 +478,4 @@ var invertTree = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md
index 6890fc2b..0df82d35 100644
--- a/problems/0232.用栈实现队列.md
+++ b/problems/0232.用栈实现队列.md
@@ -67,7 +67,7 @@ queue.empty();
C++代码如下:
-```C++
+```CPP
class MyQueue {
public:
stack stIn;
@@ -384,7 +384,7 @@ func (this *MyQueue) Peek() int {
func (this *MyQueue) Empty() bool {
return len(this.stack) == 0 && len(this.back) == 0
}
-
+```
javaScript:
@@ -442,10 +442,8 @@ MyQueue.prototype.empty = function() {
```
-
-
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0234.回文链表.md b/problems/0234.回文链表.md
index 945d2ef4..b3ad899c 100644
--- a/problems/0234.回文链表.md
+++ b/problems/0234.回文链表.md
@@ -30,7 +30,7 @@
代码也比较简单。如下:
-```C++
+```CPP
class Solution {
public:
bool isPalindrome(ListNode* head) {
@@ -51,7 +51,7 @@ public:
上面代码可以在优化,就是先求出链表长度,然后给定vector的初始长度,这样避免vector每次添加节点重新开辟空间
-```C++
+```CPP
class Solution {
public:
bool isPalindrome(ListNode* head) {
@@ -95,7 +95,7 @@ public:
代码如下:
-```C++
+```CPP
class Solution {
public:
bool isPalindrome(ListNode* head) {
@@ -148,7 +148,62 @@ public:
## Python
-```python
+```python3
+#数组模拟
+class Solution:
+ def isPalindrome(self, head: ListNode) -> bool:
+ length = 0
+ tmp = head
+ while tmp: #求链表长度
+ length += 1
+ tmp = tmp.next
+
+ result = [0] * length
+ tmp = head
+ index = 0
+ while tmp: #链表元素加入数组
+ result[index] = tmp.val
+ index += 1
+ tmp = tmp.next
+
+ i, j = 0, length - 1
+ while i < j: # 判断回文
+ if result[i] != result[j]:
+ return False
+ i += 1
+ j -= 1
+ return True
+
+#反转后半部分链表
+class Solution:
+ def isPalindrome(self, head: ListNode) -> bool:
+ if head == None or head.next == None:
+ return True
+ slow, fast = head, head
+ while fast and fast.next:
+ pre = slow
+ slow = slow.next
+ fast = fast.next.next
+
+ pre.next = None # 分割链表
+ cur1 = head # 前半部分
+ cur2 = self.reverseList(slow) # 反转后半部分,总链表长度如果是奇数,cur2比cur1多一个节点
+ while cur1:
+ if cur1.val != cur2.val:
+ return False
+ cur1 = cur1.next
+ cur2 = cur2.next
+ return True
+
+ def reverseList(self, head: ListNode) -> ListNode:
+ cur = head
+ pre = None
+ while(cur!=None):
+ temp = cur.next # 保存一下cur的下一个节点
+ cur.next = pre # 反转
+ pre = cur
+ cur = temp
+ return pre
```
## Go
@@ -166,5 +221,5 @@ public:
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0235.二叉搜索树的最近公共祖先.md b/problems/0235.二叉搜索树的最近公共祖先.md
index dffc89e6..fe875067 100644
--- a/problems/0235.二叉搜索树的最近公共祖先.md
+++ b/problems/0235.二叉搜索树的最近公共祖先.md
@@ -93,7 +93,7 @@ if (cur == NULL) return cur;
代码如下:
-```C++
+```CPP
if (cur->val > p->val && cur->val > q->val) {
TreeNode* left = traversal(cur->left, p, q);
if (left != NULL) {
@@ -147,7 +147,7 @@ return cur;
那么整体递归代码如下:
-```C++
+```CPP
class Solution {
private:
TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) {
@@ -177,7 +177,7 @@ public:
精简后代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
@@ -198,7 +198,7 @@ public:
迭代代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
@@ -360,4 +360,4 @@ var lowestCommonAncestor = function(root, p, q) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0236.二叉树的最近公共祖先.md b/problems/0236.二叉树的最近公共祖先.md
index 7b5deb56..0885e20f 100644
--- a/problems/0236.二叉树的最近公共祖先.md
+++ b/problems/0236.二叉树的最近公共祖先.md
@@ -150,7 +150,7 @@ TreeNode* right = lowestCommonAncestor(root->right, p, q);
代码如下:
-```C++
+```CPP
if (left == NULL && right != NULL) return right;
else if (left != NULL && right == NULL) return left;
else { // (left == NULL && right == NULL)
@@ -167,7 +167,7 @@ else { // (left == NULL && right == NULL)
整体代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
@@ -188,7 +188,7 @@ public:
稍加精简,代码如下:
-```C++
+```CPP
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
@@ -249,7 +249,6 @@ class Solution {
```java
// 代码精简版
class Solution {
- TreeNode pre;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root.val == p.val ||root.val == q.val) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
@@ -343,4 +342,4 @@ var lowestCommonAncestor = function(root, p, q) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md
index dedc3247..3c12a985 100644
--- a/problems/0239.滑动窗口最大值.md
+++ b/problems/0239.滑动窗口最大值.md
@@ -108,7 +108,7 @@ public:
基于刚刚说过的单调队列pop和push的规则,代码不难实现,如下:
-```C++
+```CPP
class MyQueue { //单调队列(从大到小)
public:
deque que; // 使用deque来实现单调队列
@@ -140,7 +140,7 @@ public:
C++代码如下:
-```C++
+```CPP
class Solution {
private:
class MyQueue { //单调队列(从大到小)
@@ -425,4 +425,4 @@ var maxSlidingWindow = function (nums, k) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md
index 93bba44c..b215a88a 100644
--- a/problems/0242.有效的字母异位词.md
+++ b/problems/0242.有效的字母异位词.md
@@ -61,7 +61,7 @@ https://leetcode-cn.com/problems/valid-anagram/
C++ 代码如下:
-```C++
+```CPP
class Solution {
public:
bool isAnagram(string s, string t) {
@@ -209,4 +209,4 @@ var isAnagram = function(s, t) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
-
+
diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md
index ce596396..84315507 100644
--- a/problems/0257.二叉树的所有路径.md
+++ b/problems/0257.二叉树的所有路径.md
@@ -9,7 +9,7 @@
> 以为只用了递归,其实还用了回溯
-## 257. 二叉树的所有路径
+# 257. 二叉树的所有路径
题目地址:https://leetcode-cn.com/problems/binary-tree-paths/
@@ -20,7 +20,7 @@
示例:

-## 思路
+# 思路
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
@@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) {
这里我们先使用vector结构的path容器来记录路径,那么终止处理逻辑如下:
-```C++
+```CPP
if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
string sPath;
for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
@@ -113,7 +113,7 @@ if (cur->right) {
那么回溯要怎么回溯呢,一些同学会这么写,如下:
-```C++
+```CPP
if (cur->left) {
traversal(cur->left, path, result);
}
@@ -129,7 +129,7 @@ path.pop_back();
那么代码应该这么写:
-```C++
+```CPP
if (cur->left) {
traversal(cur->left, path, result);
path.pop_back(); // 回溯
@@ -142,7 +142,7 @@ if (cur->right) {
那么本题整体代码如下:
-```C++
+```CPP
class Solution {
private:
@@ -183,7 +183,7 @@ public:
那么如上代码可以精简成如下代码:
-```C++
+```CPP
class Solution {
private:
@@ -215,8 +215,52 @@ public:
那么在如上代码中,**貌似没有看到回溯的逻辑,其实不然,回溯就隐藏在`traversal(cur->left, path + "->", result);`中的 `path + "->"`。** 每次函数调用完,path依然是没有加上"->" 的,这就是回溯了。
-**如果这里还不理解的话,可以看这篇[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA),我这这篇中详细的解释了递归中如何隐藏着回溯。 **
+为了把这份精简代码的回溯过程展现出来,大家可以试一试把:
+```CPP
+if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯就隐藏在这里
+```
+
+改成如下代码:
+
+```CPP
+path += "->";
+traversal(cur->left, path, result); // 左
+```
+
+即:
+
+```CPP
+if (cur->left) {
+ path += "->";
+ traversal(cur->left, path, result); // 左
+}
+if (cur->right) {
+ path += "->";
+ traversal(cur->right, path, result); // 右
+}
+```
+
+此时就没有回溯了,这个代码就是通过不了的了。
+
+如果想把回溯加上,就要 在上面代码的基础上,加上回溯,就可以AC了。
+
+```CPP
+if (cur->left) {
+ path += "->";
+ traversal(cur->left, path, result); // 左
+ path.pop_back(); // 回溯
+ path.pop_back();
+}
+if (cur->right) {
+ path += "->";
+ traversal(cur->right, path, result); // 右
+ path.pop_back(); // 回溯
+ path.pop_back();
+}
+```
+
+**大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的,因为并有没有改变path的数值,执行完递归函数之后,path依然是之前的数值(相当于回溯了)**
**综合以上,第二种递归的代码虽然精简但把很多重要的点隐藏在了代码细节里,第一种递归写法虽然代码多一些,但是把每一个逻辑处理都完整的展现了出来了。**
@@ -225,13 +269,14 @@ public:
## 迭代法
-至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)和[二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)。
+
+至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)和[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
这里除了模拟递归需要一个栈,同时还需要一个栈来存放对应的遍历路径。
C++代码如下:
-```C++
+```CPP
class Solution {
public:
vector binaryTreePaths(TreeNode* root) {
@@ -262,7 +307,7 @@ public:
```
当然,使用java的同学,可以直接定义一个成员变量为object的栈`Stack