Merge branch 'master' of https://github.com/youngyangyang04/leetcode-master into youngyangyang04-master

This commit is contained in:
yqq
2021-08-18 14:49:45 +08:00
241 changed files with 5051 additions and 1943 deletions

View File

@ -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<int> twoSum(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -46,7 +46,7 @@ https://leetcode-cn.com/problems/3sum/
大家可以尝试使用哈希法写一写,就知道其困难的程度了。
哈希法C++代码:
```C++
```CPP
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
@ -107,7 +107,7 @@ public:
C++代码代码如下
```C++
```CPP
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -67,7 +67,7 @@ https://leetcode-cn.com/problems/4sum/
C++代码
```C++
```CPP
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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..<nums.count {
if val != nums[fastIndex] {
if slowIndex != fastIndex {
nums[slowIndex] = nums[fastIndex]
}
slowIndex += 1
}
}
return slowIndex
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -75,7 +75,7 @@
对应的C++代码如下:
```C++
```CPP
class Solution {
public:
void nextPermutation(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)这篇文章先看了在把leetcode35.搜索插入位置做了之后做这道题目就好很多了
那么这里我采用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<int>& nums, int target) {
@ -86,7 +86,7 @@ int getRightBorder(vector<int>& nums, int target) {
## 寻找左边界
```C++
```CPP
// 二分查找寻找target的左边界leftBorder不包括target
// 如果leftBorder没有被赋值即target在数组范围的右边例如数组[3,3],target为4为了处理情况一
int getLeftBorder(vector<int>& nums, int target) {
@ -110,7 +110,7 @@ int getLeftBorder(vector<int>& nums, int target) {
左右边界计算完之后看一下主体代码这里把上面讨论的三种情况都覆盖了
```C++
```CPP
class Solution {
public:
vector<int> searchRange(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -116,7 +116,7 @@ public:
**大家要仔细看注释思考为什么要写while(left <= right) 为什么要写right = middle - 1**
```C++
```CPP
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
@ -158,7 +158,7 @@ public:
**大家要仔细看注释思考为什么要写while (left < right) 为什么要写right = middle**
```cpp
```CPP
class Solution {
public:
int searchInsert(vector<int>& 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..<nums.count {
if nums[i] >= 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -90,7 +90,7 @@ bool backtracking(vector<vector<char>>& board)
代码如下:(**详细看注释**
```C++
```CPP
bool backtracking(vector<vector<char>>& 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<vector<char>>& board) {
代码如下:
```C++
```CPP
bool isValid(int row, int col, char val, vector<vector<char>>& 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<vector<char>>& board) {
## C++代码
```C++
```CPP
class Solution {
private:
bool backtracking(vector<vector<char>>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -73,7 +73,7 @@ candidates 中的数字可以无限制重复被选取。
代码如下:
```C++
```CPP
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& candidates, int target, int sum, int startIndex)
@ -89,7 +89,7 @@ void backtracking(vector<int>& 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<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -90,7 +90,7 @@ candidates 中的每个数字在每个组合中只能使用一次。
代码如下:
```C++
```CPP
vector<vector<int>> result; // 存放组合集合
vector<int> path; // 符合条件的组合
void backtracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used) {
@ -102,7 +102,7 @@ void backtracking(vector<int>& 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<vector<int>> result;
@ -206,7 +206,7 @@ public:
这里直接用startIndex来去重也是可以的 就不用used数组了。
```C++
```CPP
class Solution {
private:
vector<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<int>& height) {
@ -152,7 +152,7 @@ public:
代码如下:
```C++
```CPP
class Solution {
public:
int trap(vector<int>& 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<int>& height) {
@ -335,7 +335,7 @@ public:
以上代码冗余了一些,但是思路是清晰的,下面我将代码精简一下,如下:
```C++
```CPP
class Solution {
public:
int trap(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -106,7 +106,7 @@ for (int i = 0; i < nums.size(); i++) {
整体C++代码如下:
```C++
```CPP
class Solution {
public:
vector<vector<int>> 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<len(nums);i++{
if !used[i]{
used[i]=true
pathNums=append(pathNums,nums[i])
backtrack(nums,pathNums,used)
pathNums=pathNums[:len(pathNums)-1]
used[i]=false
}
}
var res [][]int
func permute(nums []int) [][]int {
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)
}
for i:=0;i<numsLen;i++{
cur:=nums[i]
path = append(path,cur)
nums = append(nums[:i],nums[i+1:]...)//直接使用切片
backTrack(nums,len(nums),path)
nums = append(nums[:i],append([]int{cur},nums[i:]...)...)//回溯的时候切片也要复原,元素位置不能变
path = path[:len(path)-1]
}
}
```
@ -286,4 +289,4 @@ var permute = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<numsLen;i++{
if used[nums[i]+10]==1{
continue
}
cur:=nums[i]
path = append(path,cur)
used[nums[i]+10]=1
nums = append(nums[:i],nums[i+1:]...)
backTrack(nums,len(nums),path)
nums = append(nums[:i],append([]int{cur},nums[i:]...)...)
path = path[:len(path)-1]
func dfs(nums, path []int, used []bool) {
if len(path) == len(nums) {
res = append(res, append([]int{}, path...))
return
}
}
m := make(map[int]bool)
for i := 0; i < len(nums); i++ {
// used 从剩余 nums 中选
if used[i] {
continue
}
// m 集合间去重
if _, ok := m[nums[i]]; ok {
continue
}
m[nums[i]] = true
path = append(path, nums[i])
used[i] = true
dfs(nums, path, used)
used[i] = false
path = path[:len(path)-1]
}
}
```
@ -342,4 +338,4 @@ func backTring(nums,subRes []int,res *[][]int,used []bool){
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -171,7 +171,7 @@ bool isValid(int row, int col, vector<string>& chessboard, int n) {
## C++代码
```C++
```CPP
class Solution {
private:
vector<vector<string>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -25,7 +25,7 @@
时间复杂度O(n^2)
空间复杂度O(1)
```C++
```CPP
class Solution {
public:
int maxSubArray(vector<int>& nums) {
@ -81,7 +81,7 @@ if (count > result) result = count;
那么不难写出如下C++代码(关键地方已经注释)
```C++
```CPP
class Solution {
public:
int maxSubArray(vector<int>& nums) {
@ -109,7 +109,7 @@ public:
那么先给出我的dp代码如下有时间的录友可以提前做一做
```C++
```CPP
class Solution {
public:
int maxSubArray(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -65,7 +65,7 @@ dp[0]应该是多少呢?
以上动规五部曲分析完毕,完整代码如下:
```C++
```CPP
class Solution {
public:
int maxSubArray(vector<int>& 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;i<n;i++ {
// 这里的状态转移方程就是:求最大和
// 会面临2种情况一个是带前面的和一个是不带前面的和
dp[i] = max(dp[i-1]+nums[i],nums[i])
mx = max(mx,dp[i])
}
return mx
}
func max(a,b int) int{
if a>b {
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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -58,7 +58,7 @@ i每次移动只能在cover的范围内移动每移动一个元素cover得
C++代码如下:
```C++
```CPP
class Solution {
public:
bool canJump(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -56,7 +56,7 @@
C++代码如下
```C++
```CPP
class Solution {
public:
// 按照区间左边界从小到大排序
@ -92,7 +92,7 @@ public:
当然以上代码有冗余一些可以优化一下如下思路是一样的
```C++
```CPP
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& 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[j][0]
})
res:=[][]int{}
prev:=intervals[0]
for i:=1;i<len(intervals);i++{
cur :=intervals[i]
if prev[1]<cur[0]{
res=append(res,prev)
prev=cur
}else {
prev[1]=max(prev[1],cur[1])
}
}
res=append(res,prev)
return res
//先从小到大排序
sort.Slice(intervals,func(i,j int)bool{
return intervals[i][0]<intervals[j][0]
})
//再弄重复的
for i:=0;i<len(intervals)-1;i++{
if intervals[i][1]>=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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -66,7 +66,7 @@
整体C++代码如下:
```C++
```CPP
class Solution {
public:
vector<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -97,7 +97,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
所以本题初始化代码为:
```C++
```CPP
vector<vector<int>> dp(m, vector<int>(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<vector<int>>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -120,7 +120,7 @@ void backtracking(参数) {
可以写出如下回溯算法C++代码:
```C++
```CPP
class Solution {
private:
vector<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -0,0 +1,247 @@
# 84.柱状图中最大的矩形
链接https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210803220437.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210803220506.png)
# 思路
本题和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
其实这两道题目先做那一道都可以但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)
我们先来看一下双指针的解法:
## 双指针解法
```CPP
class Solution {
public:
int largestRectangleArea(vector<int>& 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<int>& heights) {
vector<int> minLeftIndex(heights.size());
vector<int> 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)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!
我来举一个例子,如图:
![84.柱状图中最大的矩形](https://img-blog.csdnimg.cn/20210223155303971.jpg)
只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。
所以本题单调栈的顺序正好与接雨水反过来。
此时大家应该可以发现其实就是**栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度**
理解这一点,对单调栈就掌握的比较到位了。
除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[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<int>& heights) {
stack<int> 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<int>& heights) {
stack<int> 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<len(heights) and heights[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]<heights[st[-1]]:
midh = heights[st[-1]]
st.pop()
if st!=[]:
minrightindex = i
minleftindex = st[-1]
summ = (minrightindex-minleftindex-1)*midh
result = max(summ,result)
st.append(i)
return result
```
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -124,7 +124,7 @@ public:
代码如下:
```C++
```CPP
class Solution {
private:
vector<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -183,7 +183,7 @@ void backtracking(参数) {
可以写出如下回溯算法C++代码:
```C++
```CPP
class Solution {
private:
vector<string> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -32,7 +32,7 @@
可以递归中序遍历将二叉搜索树转变成一个数组,代码如下:
```C++
```CPP
vector<int> 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<int> vec;
@ -103,7 +103,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
![二叉搜索树](https://img-blog.csdnimg.cn/20200812191501419.png)
节点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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<TreeNode*> 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<TreeNode> que= new LinkedList<TreeNode>();
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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -6,11 +6,8 @@
</p>
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 二叉树的层序遍历
看完这篇文章虽然不能打十个,但是可以迅速打八个!而且够快!
学会二叉树的层序遍历可以一口气撸完leetcode上八道题目
学会二叉树的层序遍历,可以一口气打完以下十题:
* 102.二叉树的层序遍历
* 107.二叉树的层次遍历II
@ -20,9 +17,16 @@
* 515.在每个树行中找最大值
* 116.填充每个节点的下一个右侧节点指针
* 117.填充每个节点的下一个右侧节点指针II
* 104.二叉树的最大深度
* 111.二叉树的最小深度
在之前写过这篇文章 [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)可惜当时只打了5个还不够再给我一次机会我打十个
![我要打十个](https://tva1.sinaimg.cn/large/008eGmZEly1gnadnltbpjg309603w4qp.gif)
## 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<vector<int>> 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<vector<int>> 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<int> 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<double> 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<vector<int>> 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<int> largestValues(TreeNode* root) {
@ -1042,6 +1046,31 @@ class Solution:
out_list.append(max(in_list))
return out_list
```
java代码
```java
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> retVal = new ArrayList<Integer>();
Queue<TreeNode> tmpQueue = new LinkedList<TreeNode>();
if (root != null) tmpQueue.add(root);
while (tmpQueue.size() != 0){
int size = tmpQueue.size();
List<Integer> lvlVals = new ArrayList<Integer>();
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<Node> tmpQueue = new LinkedList<Node>();
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<Node> 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]
![104. 二叉树的最大深度](https://img-blog.csdnimg.cn/20210203153031914.png)
返回它的最大深度 3 。
思路:
使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:
![层序遍历](https://img-blog.csdnimg.cn/20200810193056585.png)
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
C++代码如下:
```CPP
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> 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<TreeNode*> 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.二叉树的最小深度
如果非要打十个,还得找叶师傅!
![我要打十个](https://tva1.sinaimg.cn/large/008eGmZEly1gnadnltbpjg309603w4qp.gif)
**致敬叶师傅!**
# 其他语言版本
> 二叉树的层序遍历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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<TreeNode*> que;
queue<treenode*> 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叉树 :
![559.N叉树的最大深度](https://img-blog.csdnimg.cn/2021020315313214.png)
![559.n叉树的最大深度](https://img-blog.csdnimg.cn/2021020315313214.png)
我们应返回其最大深度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<Node*> que;
if (root != NULL) que.push(root);
int maxdepth(node* root) {
queue<node*> 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<TreeNode> deque = new LinkedList<>();
deque<treenode> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -59,7 +59,7 @@
不难写出如下代码:(先把框架写出来)
```C++
```CPP
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
// 第一步
@ -155,7 +155,7 @@ root->right = traversal(rightInorder, rightPostorder);
### C++完整代码
```C++
```CPP
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
@ -209,7 +209,7 @@ public:
加了日志的代码如下加了日志的代码不要在leetcode上提交容易超时
```C++
```CPP
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, vector<int>& 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<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
@ -419,7 +419,7 @@ public:
带日志的版本C++代码如下: **带日志的版本仅用于调试不要在leetcode上提交会超时**
```C++
```CPP
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
@ -493,7 +493,7 @@ public:
105.从前序与中序遍历序列构造二叉树最后版本C++代码:
```C++
```CPP
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -122,7 +122,7 @@ return root;
* 递归整体代码如下:
```C++
```CPP
class Solution {
private:
TreeNode* traversal(vector<int>& nums, int left, int right) {
@ -150,7 +150,7 @@ public:
模拟的就是不断分割的过程C++代码如下:(我已经详细注释)
```C++
```CPP
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<TreeNode*> st;
@ -266,7 +267,7 @@ int getDepth(TreeNode* cur) {
然后再用栈来模拟前序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,代码如下:
```
```CPP
bool isBalanced(TreeNode* root) {
stack<TreeNode*> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<TreeNode*, int>` pair<节点指针,路径数值>
定义为:`pair<treenode*, int>` 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<pair<TreeNode*, int>> st;
st.push(pair<TreeNode*, int>(root, root->val));
stack<pair<treenode*, int>> st;
st.push(pair<treenode*, int>(root, root->val));
while (!st.empty()) {
pair<TreeNode*, int> node = st.top();
pair<treenode*, int> 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<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
st.push(pair<treenode*, int>(node.first->right, node.second + node.first->right->val));
}
// 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if (node.first->left) {
st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
st.push(pair<treenode*, int>(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.路径总和II1.png](https://img-blog.csdnimg.cn/20210203160854654.png)
![113.路径总和ii1.png](https://img-blog.csdnimg.cn/20210203160854654.png)
### 思路
## 思路
113.路径总和II要遍历整个树找到所有路径**所以递归函数不要返回值!**
113.路径总和ii要遍历整个树找到所有路径**所以递归函数不要返回值!**
如图:
![113.路径总和II](https://img-blog.csdnimg.cn/20210203160922745.png)
![113.路径总和ii](https://img-blog.csdnimg.cn/20210203160922745.png)
为了尽可能的把细节体现出来,我写出如下代码(**这份代码并不简洁,但是逻辑非常清晰**
```C++
class Solution {
```cpp
class solution {
private:
vector<vector<int>> result;
vector<int> 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<vector<int>> pathSum(TreeNode* root, int sum) {
vector<vector<int>> 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<TreeNode> stack1 = new Stack<>();
Stack<Integer> stack2 = new Stack<>();
stack<treenode> stack1 = new stack<>();
stack<integer> 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<size;i++){
TreeNode node = stack1.pop();int sum=stack2.pop();
treenode node = stack1.pop();int sum=stack2.pop();
// 如果该节点是叶子节点了同时该节点的路径数值等于sum那么就返回true
if(node.left==null && node.right==null && sum==targetSum)return true;
if(node.left==null && node.right==null && sum==targetsum)return true;
// 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
if(node.right!=null){
stack1.push(node.right);stack2.push(sum+node.right.val);
@ -380,209 +378,226 @@ class Solution {
0113.路径总和-ii
```java
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> res = new ArrayList<>();
class solution {
public list<list<integer>> pathsum(treenode root, int targetsum) {
list<list<integer>> res = new arraylist<>();
if (root == null) return res; // 非空判断
List<Integer> path = new LinkedList<>();
preorderDFS(root, targetSum, res, path);
list<integer> path = new linkedlist<>();
preorderdfs(root, targetsum, res, path);
return res;
}
public void preorderDFS(TreeNode root, int targetSum, List<List<Integer>> res, List<Integer> path) {
public void preorderdfs(treenode root, int targetsum, list<list<integer>> res, list<integer> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -82,7 +82,7 @@ dp[0][0]应该是1空字符串s可以删除0个元素变成空字符串
初始化分析完毕,代码如下:
```C++
```CPP
vector<vector<long long>> dp(s.size() + 1, vector<long long>(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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<Node> que = new LinkedList<Node>();
que.offer(root);
Node nodePre = null;
Node node = null;
while (!que.isEmpty()) {
int size = que.size();
for (int i=0; i<size; i++) { // 开始每一层的遍历
if (i == 0) {
nodePre = que.peek(); // 记录一层的头结点
que.poll();
node = nodePre;
} else {
node = que.peek();
que.poll();
nodePre.next = node; // 本层前一个节点next指向本节点
nodePre = nodePre.next;
}
if (node.left != null) que.offer(node.left);
if (node.right != null) que.offer(node.right);
}
nodePre.next = null; // 本层最后一个节点指向null
}
return root;
}
}
```
## Python
```python
# 递归法
class Solution:
def connect(self, root: 'Node') -> '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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -33,7 +33,7 @@
这道题目最直观的想法,就是暴力,找最优间距了。
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& prices) {
@ -59,7 +59,7 @@ public:
C++代码如下:
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -80,7 +80,7 @@
对应C++代码如下:
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& prices) {
@ -99,7 +99,7 @@ public:
动态规划将在下一个系列详细讲解本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -74,7 +74,7 @@
代码如下注意代码中的注释标记了和121.买卖股票的最佳时机唯一不同的地方)
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -52,7 +52,7 @@ if (!cur->left && !cur->right) { // 遇到了叶子节点
这里vectorToInt函数就是把数组转成int代码如下
```C++
```CPP
int vectorToInt(const vector<int>& vec) {
int sum = 0;
for (int i = 0; i < vec.size(); i++) {
@ -78,7 +78,7 @@ int vectorToInt(const vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -70,7 +70,7 @@
代码如下:
```C++
```CPP
vector<vector<string>> result;
vector<string> 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<vector<string>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -101,7 +101,7 @@ dp[i] 范围是[0, i]的回文子串最少分割次数是dp[i]。
代码如下:
```C++
```CPP
vector<int> dp(s.size(), INT_MAX);
dp[0] = 0;
```
@ -109,7 +109,7 @@ dp[0] = 0;
其实也可以这样初始化更具dp[i]的定义dp[i]的最大值其实就是i也就是把每个字符分割出来。
所以初始化代码也可以为:
```C++
```CPP
vector<int> dp(s.size());
for (int i = 0; i < s.size(); i++) dp[i] = i;
```
@ -122,7 +122,7 @@ j是在[0i]之间所以遍历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<vector<bool>> isPalindromic(s.size(), vector<bool>(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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -65,7 +65,7 @@ cost = [3,4,3]
C++代码如下:
```C++
```CPP
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
@ -99,7 +99,7 @@ C++暴力解法在leetcode上提交也可以过。
C++代码如下:
```C++
```CPP
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
@ -160,7 +160,7 @@ i从0开始累加rest[i]和记为curSum一旦curSum小于零说明[0, i
C++代码如下:
```C++
```CPP
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -45,7 +45,7 @@
那么这里我也给出回溯法C++代码:
```C++
```CPP
class Solution {
private:
bool backtracking (const string& s, const unordered_set<string>& 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<string>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -14,7 +14,7 @@
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1则在该链表中没有环。注意pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
 
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210727173600.png)
# 思路
@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -1,4 +1,3 @@
<p align="center">
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -80,7 +80,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
C++代码如下:
```C++
```CPP
class Solution {
public:
int evalRPN(vector<string>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -1,2 +1,3 @@
同:[链表:链表相交](./面试题02.07.链表相交.md)
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -84,7 +84,7 @@ vector<vector<int>> dp(prices.size(), vector<int>(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<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -69,7 +69,7 @@
C++代码如下:
```C++
```CPP
class Solution {
public:
void rotate(vector<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -25,7 +25,7 @@
输出12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
  偷窃到的最高金额 = 2 + 9 + 1 = 12 。
 
提示:
@ -59,7 +59,7 @@
代码如下:
```C++
```CPP
vector<int> 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<int>& 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<Character, Character> map1 = new HashMap<>();
Map<Character, Character> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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 = headpre = 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -26,7 +26,7 @@
代码如下:
```C++
```CPP
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
@ -86,7 +86,7 @@ public:
C++代码如下:
```C++
```CPP
class Solution {
public:
int minSubArrayLen(int s, vector<int>& 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..<nums.count {
sum += nums[endIndex]
while sum >= 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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<vector<int>> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -7,24 +7,23 @@
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -65,7 +65,7 @@ queue.empty();
详细如代码注释所示:
```C++
```CPP
class MyStack {
public:
queue<int> que1;
@ -118,7 +118,7 @@ public:
C++优化代码
```C++
```CPP
class MyStack {
public:
queue<int> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -67,7 +67,7 @@ queue.empty();
C++代码如下:
```C++
```CPP
class MyQueue {
public:
stack<int> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -108,7 +108,7 @@ public:
基于刚刚说过的单调队列pop和push的规则代码不难实现如下
```C++
```CPP
class MyQueue { //单调队列(从大到小)
public:
deque<int> 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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -9,7 +9,7 @@
> 以为只用了递归,其实还用了回溯
## 257. 二叉树的所有路径
# 257. 二叉树的所有路径
题目地址https://leetcode-cn.com/problems/binary-tree-paths/
@ -20,7 +20,7 @@
示例:
![257.二叉树的所有路径1](https://img-blog.csdnimg.cn/2021020415161576.png)
## 思路
# 思路
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) {
这里我们先使用vector<int>结构的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<string> binaryTreePaths(TreeNode* root) {
@ -262,7 +307,7 @@ public:
```
当然使用java的同学可以直接定义一个成员变量为object的栈`Stack<Object> stack = new Stack<>();`,这样就不用定义两个栈了,都放到一个栈里就可以了。
## 总结
# 总结
**本文我们开始初步涉及到了回溯,很多同学过了这道题目,可能都不知道自己其实使用了回溯,回溯和递归都是相伴相生的。**
@ -278,7 +323,7 @@ public:
## 其他语言版本
# 其他语言版本
Java
@ -321,62 +366,10 @@ class Solution {
}
}
}
//解法二(常规前序遍历,不用回溯),更容易理解
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
helper(root, new StringBuilder(), res);
return res;
}
public void helper(TreeNode root, StringBuilder sb, List<String> res) {
if (root == null) {return;}
// 遇到叶子结点就放入当前路径到res集合中
if (root.left == null && root.right ==null) {
sb.append(root.val);
res.add(sb.toString());
// 记得结束当前方法
return;
}
helper(root.left,new StringBuilder(sb).append(root.val + "->"),res);
helper(root.right,new StringBuilder(sb).append(root.val + "->"),res);
}
}
//针对解法二优化,思路本质是一样的
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
helper(root, "", res);
return res;
}
public void helper(TreeNode root, String path, List<String> res) {
if (root == null) {return;}
// 由原始解法二可以知道root的值肯定会下面某一个条件加入到path中那么干脆直接在这一步加入即可
StringBuilder sb = new StringBuilder(path);
sb.append(root.val);
if (root.left == null && root.right ==null) {
res.add(sb.toString());
}else{
// 如果是非叶子结点则还需要跟上一个 “->”
sb.append("->");
helper(root.left,sb.toString(),res);
helper(root.right,sb.toString(),res);
}
}
}
```
Python
```Python
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
path=[]
@ -396,8 +389,8 @@ class Solution:
return ["->".join(list(map(str,i))) for i in res]
```
Go
Go
```go
func binaryTreePaths(root *TreeNode) []string {
res := make([]string, 0)
@ -422,7 +415,9 @@ func binaryTreePaths(root *TreeNode) []string {
```
JavaScript:
1.递归版本
```javascript
var binaryTreePaths = function(root) {
//递归遍历+递归三部曲
@ -452,4 +447,4 @@ var binaryTreePaths = function(root) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -76,7 +76,7 @@ dp[0]表示 和为0的完全平方数的最小数量那么dp[0]一定是0。
我这里先给出外层遍历背包,里层遍历物品的代码:
```C++
```CPP
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for (int i = 0; i <= n; i++) { // 遍历背包
@ -106,7 +106,7 @@ dp[5] = min(dp[4] + 1, dp[1] + 1) = 2
以上动规五部曲分析完毕C++代码如下:
```C++
```CPP
// 版本一
class Solution {
public:
@ -125,7 +125,7 @@ public:
同样我在给出先遍历物品在遍历背包的代码一样的可以AC的。
```C++
```CPP
// 版本二
class Solution {
public:
@ -286,10 +286,38 @@ func min(a, b int) int {
}
```
Javascript:
```Javascript
// 先遍历物品,再遍历背包
var numSquares1 = function(n) {
let dp = new Array(n + 1).fill(Infinity)
dp[0] = 0
for(let i = 0; i <= n; i++) {
let val = i * i
for(let j = val; j <= n; j++) {
dp[j] = Math.min(dp[j], dp[j - val] + 1)
}
}
return dp[n]
};
// 先遍历背包,再遍历物品
var numSquares2 = function(n) {
let dp = new Array(n + 1).fill(Infinity)
dp[0] = 0
for(let i = 1; i <= n; i++) {
for(let j = 1; j * j <= i; j++) {
dp[i] = Math.min(dp[i - j * j] + 1, dp[i])
}
}
return dp[n]
};
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -42,7 +42,7 @@
C++代码如下:
```C++
```CPP
class Solution {
public:
void moveZeroes(vector<int>& nums) {
@ -64,6 +64,21 @@ public:
Java
```java
public void moveZeroes(int[] nums) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != 0) {
nums[slow++] = nums[fast];
}
}
// 后面的元素全变成 0
for (int j = slow; j < nums.length; j++) {
nums[j] = 0;
}
}
```
Python
```python
@ -85,5 +100,5 @@ JavaScript
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -60,7 +60,7 @@ dp[i] 是有0到i-1各个位置的最长升序子序列 推导而来,那么遍
j其实就是0到i-1遍历i的循环里外层遍历j则在内层代码如下
```C++
```CPP
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
@ -80,7 +80,7 @@ for (int i = 1; i < nums.size(); i++) {
以上五部分析完毕C++代码如下:
```C++
```CPP
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
@ -198,4 +198,4 @@ const lengthOfLIS = (nums) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -95,7 +95,7 @@ p[i][3] = dp[i - 1][2];
综上分析,递推代码如下:
```C++
```CPP
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i];
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
dp[i][2] = dp[i - 1][0] + prices[i];
@ -129,7 +129,7 @@ dp[i][3] = dp[i - 1][2];
代码如下:
```C++
```CPP
class Solution {
public:
int maxProfit(vector<int>& prices) {
@ -236,4 +236,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)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -112,7 +112,7 @@ dp[amount]为最终结果。
## C++代码
以上分析完毕C++ 代码如下:
```C++
```CPP
// 版本一
class Solution {
public:
@ -134,7 +134,7 @@ public:
对于遍历方式遍历背包放在外循环,遍历物品放在内循环也是可以的,我就直接给出代码了
```C++
```CPP
// 版本二
class Solution {
public:
@ -330,4 +330,4 @@ const coinChange = (coins, amount) => {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -178,7 +178,7 @@ if (result.size() == ticketNum + 1) {
遍历过程如下:
```C++
```CPP
for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
if (target.second > 0 ) { // 记录到达机场是否飞过了
result.push_back(target.first);
@ -194,7 +194,7 @@ for (pair<const string, int>& target : targets[result[result.size() - 1]]) {
分析完毕此时完整C++代码如下:
```C++
```CPP
class Solution {
private:
// unordered_map<出发机场, map<到达机场, 航班次数>> targets
@ -450,4 +450,4 @@ var findItinerary = function(tickets) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -35,7 +35,7 @@
代码如下:
```C++
```CPP
class Solution {
public:
int rob(TreeNode* root) {
@ -65,7 +65,7 @@ public:
代码如下:
```C++
```CPP
class Solution {
public:
unordered_map<TreeNode* , int> umap; // 记录计算过的结果
@ -103,7 +103,7 @@ public:
参数为当前节点,代码如下:
```C++
```CPP
vector<int> robTree(TreeNode* cur) {
```
@ -138,7 +138,7 @@ if (cur == NULL) return vector<int>{0, 0};
代码如下:
```C++
```CPP
// 下标0不偷下标1
vector<int> left = robTree(cur->left); // 左
vector<int> right = robTree(cur->right); // 右
@ -156,7 +156,7 @@ vector<int> right = robTree(cur->right); // 右
代码如下:
```C++
```CPP
vector<int> left = robTree(cur->left); // 左
vector<int> right = robTree(cur->right); // 右
@ -179,7 +179,7 @@ return {val2, val1};
递归三部曲与动规五部曲分析完毕C++代码如下:
```C++
```CPP
class Solution {
public:
int rob(TreeNode* root) {
@ -368,7 +368,32 @@ class Solution:
return (val1, val2)
```
Go
JavaScript
> 动态规划
```javascript
const rob = root => {
// 后序遍历函数
const postOrder = node => {
// 递归出口
if (!node) return [0, 0];
// 遍历左子树
const left = postOrder(node.left);
// 遍历右子树
const right = postOrder(node.right);
// 不偷当前节点,左右子节点都可以偷或不偷,取最大值
const DoNot = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
// 偷当前节点,左右子节点只能不偷
const Do = node.val + left[0] + right[0];
// [不偷,偷]
return [DoNot, Do];
};
const res = postOrder(root);
// 返回最大值
return Math.max(...res);
};
```
@ -377,4 +402,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -59,6 +59,10 @@ j是从1开始遍历拆分j的情况在遍历j的过程中其实都计算
所以递推公式dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});
那么在取最大值的时候为什么还要比较dp[i]呢?
因为在递推公式推导的过程中每次计算dp[i],取最大的而已。
3. dp的初始化
@ -101,7 +105,7 @@ for (int i = 3; i <= n ; i++) {
以上动规五部曲分析完毕C++代码如下:
```C++
```CPP
class Solution {
public:
int integerBreak(int n) {
@ -128,7 +132,7 @@ public:
给出我的C++代码如下:
```C++
```CPP
class Solution {
public:
int integerBreak(int n) {
@ -154,7 +158,7 @@ public:
其实这道题目的递推公式并不好想,而且初始化的地方也很有讲究,我在写本题的时候一开始写的代码是这样的:
```C++
```CPP
class Solution {
public:
int integerBreak(int n) {
@ -244,4 +248,4 @@ var integerBreak = function(n) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -74,7 +74,7 @@ https://leetcode-cn.com/problems/reverse-string/
不难写出如下C++代码:
```C++
```CPP
void reverseString(vector<char>& s) {
for (int i = 0, j = s.size() - 1; i < s.size()/2; i++, j--) {
swap(s[i],s[j]);
@ -90,7 +90,7 @@ swap可以有两种实现。
一种就是常见的交换数值:
```C++
```CPP
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
@ -99,7 +99,7 @@ s[j] = tmp;
一种就是通过位运算:
```C++
```CPP
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
@ -120,7 +120,7 @@ s[i] ^= s[j];
C++代码如下:
```C++
```CPP
class Solution {
public:
void reverseString(vector<char>& s) {
@ -219,4 +219,4 @@ var reverseString = function(s) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -76,7 +76,7 @@ https://leetcode-cn.com/problems/top-k-frequent-elements/
我们来看一下C++代码:
```C++
```CPP
// 时间复杂度O(nlogk)
// 空间复杂度O(n)
class Solution {
@ -190,10 +190,105 @@ class Solution:
Go
javaScript:
```js
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var topKFrequent = function(nums, k) {
const map = new Map();
for(const num of nums) {
map.set(num, (map.get(num) || 0) + 1);
}
// 创建小顶堆
const priorityQueue = new PriorityQueue((a, b) => a[1] - b[1]);
// entry 是一个长度为2的数组0位置存储key1位置存储value
for (const entry of map.entries()) {
priorityQueue.push(entry);
if (priorityQueue.size() > k) {
priorityQueue.pop();
}
}
const ret = [];
for(let i = priorityQueue.size() - 1; i >= 0; i--) {
ret[i] = priorityQueue.pop()[0];
}
return ret;
};
function PriorityQueue(compareFn) {
this.compareFn = compareFn;
this.queue = [];
}
// 添加
PriorityQueue.prototype.push = function(item) {
this.queue.push(item);
let index = this.queue.length - 1;
let parent = Math.floor((index - 1) / 2);
// 上浮
while(parent >= 0 && this.compare(parent, index) > 0) {
// 交换
[this.queue[index], this.queue[parent]] = [this.queue[parent], this.queue[index]];
index = parent;
parent = Math.floor((index - 1) / 2);
}
}
// 获取堆顶元素并移除
PriorityQueue.prototype.pop = function() {
const ret = this.queue[0];
// 把最后一个节点移到堆顶
this.queue[0] = this.queue.pop();
let index = 0;
// 左子节点下标left + 1 就是右子节点下标
let left = 1;
let selectedChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
// 下沉
while(selectedChild !== undefined && this.compare(index, selectedChild) > 0) {
// 交换
[this.queue[index], this.queue[selectedChild]] = [this.queue[selectedChild], this.queue[index]];
index = selectedChild;
left = 2 * index + 1;
selectedChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
}
return ret;
}
PriorityQueue.prototype.size = function() {
return this.queue.length;
}
// 使用传入的 compareFn 比较两个位置的元素
PriorityQueue.prototype.compare = function(index1, index2) {
if (this.queue[index1] === undefined) {
return 1;
}
if (this.queue[index2] === undefined) {
return -1;
}
return this.compareFn(this.queue[index1], this.queue[index2]);
}
```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -54,7 +54,7 @@ std::set和std::multiset底层实现都是红黑树std::unordered_set的底
C++代码如下:
```C++
```CPP
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
@ -121,13 +121,7 @@ Python
```python
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
result_set = set()
set1 = set(nums1)
for num in nums2:
if num in set1:
result_set.add(num) # set1里出现的nums2元素 存放到结果
return result_set
return list(set(nums1) & set(nums2)) # 两个数组先变成集合,求交集后还原为数组
```
@ -188,4 +182,4 @@ var intersection = function(nums1, nums2) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -70,7 +70,7 @@
C++代码如下(和上图是对应的逻辑):
```C++
```CPP
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
@ -192,4 +192,4 @@ var wiggleMaxLength = function(nums) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -107,7 +107,7 @@ dp[i]考虑nums[j])可以由 dp[i - nums[j]]不考虑nums[j] 推导
以上分析完毕C++代码如下:
```C++
```CPP
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
@ -226,4 +226,4 @@ const combinationSum4 = (nums, target) => {
* 作者微信[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

View File

@ -40,7 +40,7 @@ canConstruct("aa", "aab") -> true
那么第一个思路其实就是暴力枚举了两层for循环不断去寻找代码如下
```C++
```CPP
// 时间复杂度: O(n^2)
// 空间复杂度O(1)
class Solution {
@ -79,7 +79,7 @@ public:
代码如下:
```C++
```CPP
// 时间复杂度: O(n)
// 空间复杂度O(1)
class Solution {
@ -209,6 +209,22 @@ class Solution(object):
return True
```
Python写法四
```python3
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
c1 = collections.Counter(ransomNote)
c2 = collections.Counter(magazine)
x = c1 - c2
#x只保留值大于0的符号当c1里面的符号个数小于c2时不会被保留
#所以x只保留下了magazine不能表达的
if(len(x)==0):
return True
else:
return False
```
Go
```go
@ -256,4 +272,4 @@ var canConstruct = function(ransomNote, magazine) {
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>

Some files were not shown because too many files have changed in this diff Show More