Merge branch 'youngyangyang04:master' into master

This commit is contained in:
ironartisan
2021-08-25 16:50:59 +08:00
committed by GitHub
21 changed files with 410 additions and 442 deletions

View File

@ -13,7 +13,7 @@
# 150. 逆波兰表达式求值 # 150. 逆波兰表达式求值
[力扣题目链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/) https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
根据 逆波兰表示法,求表达式的值。 根据 逆波兰表示法,求表达式的值。
@ -23,7 +23,7 @@
整数除法只保留整数部分。 整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
 
示例 1 示例 1
* 输入: ["2", "1", "+", "3", " * "] * 输入: ["2", "1", "+", "3", " * "]
@ -40,13 +40,13 @@
* 输出: 22 * 输出: 22
* 解释:该算式转化为常见的中缀算术表达式为: * 解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5 ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5 = ((10 * 0) + 17) + 5
= (0 + 17) + 5 = (0 + 17) + 5
= 17 + 5 = 17 + 5
= 22 = 22
 
逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。 逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。
@ -62,7 +62,7 @@
# 思路 # 思路
在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。 在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)提到了 递归就是用栈来实现的。
所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。 所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。
@ -70,12 +70,12 @@
但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。 但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。** 在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中的对对碰游戏是不是就非常像了。**
如动画所示: 如动画所示:
![150.逆波兰表达式求值](https://code-thinking.cdn.bcebos.com/gifs/150.逆波兰表达式求值.gif) ![150.逆波兰表达式求值](https://code-thinking.cdn.bcebos.com/gifs/150.逆波兰表达式求值.gif)
相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不错的,只不过本题不要相邻元素做消除了,而是做运算! 相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
C++代码如下: C++代码如下:
@ -223,17 +223,19 @@ var evalRPN = function(tokens) {
python3 python3
```python ```python
def evalRPN(tokens) -> int: class Solution:
stack = list() def evalRPN(self, tokens: List[str]) -> int:
for i in range(len(tokens)): stack = []
if tokens[i] not in ["+", "-", "*", "/"]: for item in tokens:
stack.append(tokens[i]) if item not in {"+", "-", "*", "/"}:
else: stack.append(item)
tmp1 = stack.pop() else:
tmp2 = stack.pop() first_num, second_num = stack.pop(), stack.pop()
res = eval(tmp2+tokens[i]+tmp1) stack.append(
stack.append(str(int(res))) int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面
return stack[-1] )
return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的
``` ```

View File

@ -12,7 +12,7 @@
# 225. 用队列实现栈 # 225. 用队列实现栈
[力扣题目链接](https://leetcode-cn.com/problems/implement-stack-using-queues/) https://leetcode-cn.com/problems/implement-stack-using-queues/
使用队列实现栈的下列操作: 使用队列实现栈的下列操作:
@ -34,7 +34,7 @@
有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!** 有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!**
刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://programmercarl.com/0232.用栈实现队列.html)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行! 刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://mp.weixin.qq.com/s/Cj6R0qu8rFA7Et9V_ZMjCA)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!
**队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。 **队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。
@ -294,53 +294,66 @@ Python
```python ```python
from collections import deque from collections import deque
class MyStack: class MyStack:
def __init__(self): def __init__(self):
""" """
Initialize your data structure here. Python普通的Queue或SimpleQueue没有类似于peek的功能
也无法用索引访问在实现top的时候较为困难。
用list可以但是在使用pop(0)的时候时间复杂度为O(n)
因此这里使用双向队列我们保证只执行popleft()和append()因为deque可以用索引访问可以实现和peek相似的功能
in - 存所有数据
out - 仅在pop的时候会用到
""" """
#使用两个队列来实现 self.queue_in = deque()
self.que1 = deque() self.queue_out = deque()
self.que2 = deque()
def push(self, x: int) -> None: def push(self, x: int) -> None:
""" """
Push element x onto stack. 直接append即可
""" """
self.que1.append(x) self.queue_in.append(x)
def pop(self) -> int: def pop(self) -> int:
""" """
Removes the element on top of the stack and returns that element. 1. 首先确认不空
2. 因为队列的特殊性FIFO所以我们只有在pop()的时候才会使用queue_out
3. 先把queue_in中的所有元素除了最后一个依次出列放进queue_out
4. 交换in和out此时out里只有一个元素
5. 把out中的pop出来即是原队列的最后一个
tip这不能像栈实现队列一样因为另一个queue也是FIFO如果执行pop()它不能像
stack一样从另一个pop()所以干脆in只用来存数据pop()的时候两个进行交换
""" """
size = len(self.que1) if self.empty():
size -= 1#这里先减一是为了保证最后面的元素 return None
while size > 0:
size -= 1
self.que2.append(self.que1.popleft())
for i in range(len(self.queue_in) - 1):
result = self.que1.popleft() self.queue_out.append(self.queue_in.popleft())
self.que1, self.que2= self.que2, self.que1#将que2和que1交换 que1经过之前的操作应该是空了
#一定注意不能直接使用que1 = que2 这样que2的改变会影响que1 可以用浅拷贝 self.queue_in, self.queue_out = self.queue_out, self.queue_in # 交换in和out这也是为啥in只用来存
return result return self.queue_out.popleft()
def top(self) -> int: def top(self) -> int:
""" """
Get the top element. 1. 首先确认不空
2. 我们仅有in会存放数据所以返回第一个即可
""" """
return self.que1[-1] if self.empty():
return None
return self.queue_in[-1]
def empty(self) -> bool: def empty(self) -> bool:
""" """
Returns whether the stack is empty. 因为只有in存了数据只要判断in是不是有数即可
""" """
#print(self.que1) return len(self.queue_in) == 0
if len(self.que1) == 0:
return True
else:
return False
``` ```

View File

@ -11,7 +11,7 @@
# 232.用栈实现队列 # 232.用栈实现队列
[力扣题目链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/) https://leetcode-cn.com/problems/implement-queue-using-stacks/
使用栈实现队列的下列操作: 使用栈实现队列的下列操作:
@ -129,54 +129,6 @@ public:
Java Java
使用Stack(堆栈)同名方法:
```java
class MyQueue {
// java中的 Stack 有设计上的缺陷,官方推荐使用 Deque(双端队列) 代替 Stack
Deque<Integer> stIn;
Deque<Integer> stOut;
/** Initialize your data structure here. */
public MyQueue() {
stIn = new ArrayDeque<>();
stOut = new ArrayDeque<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
stIn.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
// 只要 stOut 为空,那么就应该将 stIn 中所有的元素倒腾到 stOut 中
if (stOut.isEmpty()) {
while (!stIn.isEmpty()) {
stOut.push(stIn.pop());
}
}
// 再返回 stOut 中的元素
return stOut.pop();
}
/** Get the front element. */
public int peek() {
// 直接使用已有的pop函数
int res = this.pop();
// 因为pop函数弹出了元素res所以再添加回去
stOut.push(res);
return res;
}
/** Returns whether the queue is empty. */
public boolean empty() {
// 当 stIn 栈为空时,说明没有元素可以倒腾到 stOut 栈了
// 并且 stOut 栈也为空时,说明没有以前从 stIn 中倒腾到的元素了
return stIn.isEmpty() && stOut.isEmpty();
}
}
```
```java ```java
class MyQueue { class MyQueue {
@ -234,48 +186,60 @@ class MyQueue {
Python Python
```python ```python
# 使用两个栈实现先进先出的队列
class MyQueue: class MyQueue:
def __init__(self): def __init__(self):
""" """
Initialize your data structure here. in主要负责pushout主要负责pop
""" """
self.stack1 = list() self.stack_in = []
self.stack2 = list() self.stack_out = []
def push(self, x: int) -> None: def push(self, x: int) -> None:
""" """
Push element x to the back of queue. 有新元素进来就往in里面push
""" """
# self.stack1用于接受元素 self.stack_in.append(x)
self.stack1.append(x)
def pop(self) -> int: def pop(self) -> int:
""" """
Removes the element from in front of queue and returns that element. 1. 检查如果out里面元素则直接pop
2. 如果out没有元素就把in里面的元素除了第一个依次pop后装进out里面
3. 直接把in剩下的元素pop出来就是queue头部的
""" """
# self.stack2用于弹出元素如果self.stack2为[],则将self.stack1中元素全部弹出给self.stack2 if self.empty:
if self.stack2 == []: return None
while self.stack1:
tmp = self.stack1.pop() if self.stack_out:
self.stack2.append(tmp) return self.stack_out.pop()
return self.stack2.pop() else:
for i in range(1, len(self.stack_in)):
self.stack_out.append(self.stack_in.pop())
return self.stack_in.pop()
def peek(self) -> int: def peek(self) -> int:
""" """
Get the front element. 1. 查out有没有元素有就把最上面的返回
2. 如果out没有元素就把in最下面的返回
""" """
if self.stack2 == []: if self.empty:
while self.stack1: return None
tmp = self.stack1.pop()
self.stack2.append(tmp) if self.stack_out:
return self.stack2[-1] return self.stack_out[-1]
else:
return self.stack_in[0]
def empty(self) -> bool: def empty(self) -> bool:
""" """
Returns whether the queue is empty. 只要in或者out有元素说明队列不为空
""" """
return self.stack1 == [] and self.stack2 == [] return not (self.stack_in or self.stack_out)
``` ```

View File

@ -9,7 +9,7 @@
## 279.完全平方数 ## 279.完全平方数
[力扣题目链接](https://leetcode-cn.com/problems/perfect-squares/) 题目地址:https://leetcode-cn.com/problems/perfect-squares/
给定正整数 n找到若干个完全平方数比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 给定正整数 n找到若干个完全平方数比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
@ -36,7 +36,7 @@
**我来把题目翻译一下完全平方数就是物品可以无限件使用凑个正整数n就是背包问凑满这个背包最少有多少物品** **我来把题目翻译一下完全平方数就是物品可以无限件使用凑个正整数n就是背包问凑满这个背包最少有多少物品**
感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)就是一样一样的! 感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)就是一样一样的!
动规五部曲分析如下: 动规五部曲分析如下:
@ -70,7 +70,7 @@ dp[0]表示 和为0的完全平方数的最小数量那么dp[0]一定是0。
如果求排列数就是外层for遍历背包内层for循环遍历物品。 如果求排列数就是外层for遍历背包内层for循环遍历物品。
在[动态规划322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)中我们就深入探讨了这个问题,本题也是一样的,是求最小数! 在[动态规划322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)中我们就深入探讨了这个问题,本题也是一样的,是求最小数!
**所以本题外层for遍历背包里层for遍历物品还是外层for遍历物品内层for遍历背包都是可以的** **所以本题外层for遍历背包里层for遍历物品还是外层for遍历物品内层for遍历背包都是可以的**
@ -146,7 +146,7 @@ public:
## 总结 ## 总结
如果大家认真做了昨天的题目[动态规划322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html),今天这道就非常简单了,一样的套路一样的味道。 如果大家认真做了昨天的题目[动态规划322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ),今天这道就非常简单了,一样的套路一样的味道。
但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的! 但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的!
@ -161,6 +161,7 @@ public:
Java Java
```Java ```Java
class Solution { class Solution {
// 版本一,先遍历物品, 再遍历背包
public int numSquares(int n) { public int numSquares(int n) {
int max = Integer.MAX_VALUE; int max = Integer.MAX_VALUE;
int[] dp = new int[n + 1]; int[] dp = new int[n + 1];
@ -170,7 +171,9 @@ class Solution {
} }
//当和为0时组合的个数为0 //当和为0时组合的个数为0
dp[0] = 0; dp[0] = 0;
// 遍历物品
for (int i = 1; i * i <= n; i++) { for (int i = 1; i * i <= n; i++) {
// 遍历背包
for (int j = i * i; j <= n; j++) { for (int j = i * i; j <= n; j++) {
if (dp[j - i * i] != max) { if (dp[j - i * i] != max) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1); dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
@ -180,6 +183,28 @@ class Solution {
return dp[n]; return dp[n];
} }
} }
class Solution {
// 版本二, 先遍历背包, 再遍历物品
public int numSquares(int n) {
int max = Integer.MAX_VALUE;
int[] dp = new int[n + 1];
// 初始化
for (int j = 0; j <= n; j++) {
dp[j] = max;
}
// 当和为0时组合的个数为0
dp[0] = 0;
// 遍历背包
for (int j = 1; j <= n; j++) {
// 遍历物品
for (int i = 1; i * i <= j; i++) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
return dp[n];
}
}
``` ```
Python Python
@ -187,7 +212,7 @@ Python
```python3 ```python3
class Solution: class Solution:
def numSquares(self, n: int) -> int: def numSquares(self, n: int) -> int:
'''版本一''' '''版本一,先遍历背包, 再遍历物品'''
# 初始化 # 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n] nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1) dp = [10**4]*(n + 1)
@ -201,7 +226,7 @@ class Solution:
return dp[n] return dp[n]
def numSquares1(self, n: int) -> int: def numSquares1(self, n: int) -> int:
'''版本二''' '''版本二 先遍历物品, 再遍历背包'''
# 初始化 # 初始化
nums = [i**2 for i in range(1, n + 1) if i**2 <= n] nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
dp = [10**4]*(n + 1) dp = [10**4]*(n + 1)
@ -217,6 +242,22 @@ class Solution:
Python3: Python3:
```python ```python
class Solution: class Solution:
'''版本一,先遍历背包, 再遍历物品'''
def numSquares(self, n: int) -> int:
dp = [n] * (n + 1)
dp[0] = 0
# 遍历背包
for j in range(1, n+1):
for i in range(1, n):
num = i ** 2
if num > j: break
# 遍历物品
if j - num >= 0:
dp[j] = min(dp[j], dp[j - num] + 1)
return dp[n]
class Solution:
'''版本二, 先遍历物品, 再遍历背包'''
def numSquares(self, n: int) -> int: def numSquares(self, n: int) -> int:
# 初始化 # 初始化
# 组成和的完全平方数的最多个数就是只用1构成 # 组成和的完全平方数的最多个数就是只用1构成

View File

@ -8,13 +8,13 @@
## 300.最长递增子序列 ## 300.最长递增子序列
[力扣题目链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/) 题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
 
示例 1 示例 1
输入nums = [10,9,2,5,3,7,101,18] 输入nums = [10,9,2,5,3,7,101,18]
输出4 输出4
@ -27,13 +27,12 @@
示例 3 示例 3
输入nums = [7,7,7,7,7,7,7] 输入nums = [7,7,7,7,7,7,7]
输出1 输出1
 
提示: 提示:
* 1 <= nums.length <= 2500 * 1 <= nums.length <= 2500
* -10^4 <= nums[i] <= 104 * -10^4 <= nums[i] <= 104
## 方法一 动态规划
## 思路 ## 思路
最长上升子序列是动规的经典题目这里dp[i]是可以根据dp[j] j < i推导出来的那么依然用动规五部曲来分析详细一波 最长上升子序列是动规的经典题目这里dp[i]是可以根据dp[j] j < i推导出来的那么依然用动规五部曲来分析详细一波
@ -189,121 +188,6 @@ const lengthOfLIS = (nums) => {
return result; return result;
}; };
``` ```
*复杂度分析*
- 时间复杂度O(n^2)。数组 nums 的长度为 n我们依次用数组中的元素去遍历 dp 数组,而遍历 dp 数组时需要进行 O(n) 次搜索,所以总时间复杂度为 O(n^2)。
- 空间复杂度O(n),需要额外使用长度为 n 的 dp 数组。
## 方法二 贪心策略+二分搜索
使用贪心策略和二分搜索可以进一步将算法时间复杂度将为O(nlogn)。
## 思路
为了使得到的子序列尽可能长,我们需要使序列上升得尽可能慢。
对于长度为n的数组 nums我们从0到n-1依次遍历数组中的每个元素nums[i],更新在0到i范围内最长上升子序列的长度len以及 在0到i范围内上升子序列的长度为1到len时对应长度子序列最右端的最小值将结果保存在list中。实际编码过程中list长度即为len。
## 可行性
当我们遍历完数组nums中第n-1个元素时list中保存的是0到n-1范围内最长上升子序列的长度即为所求。
## 算法复杂度分析
1. list中的元素是单调递增的。可以用反证法来证明假设对于0<=i<j<len有list[i]>=list[j]那么我们可以在list[j]对应的子序列中删除最后j-i个元素得到长度与list[i]相同的子序列其最右端的值max<list[j]<=list[i],与list的定义矛盾
2. 假设我们已经得到0到i-1范围内对应的list,我们可以在O(logn)的时间复杂度内更新list,得到0到i范围内的list
1. if(nums[i]>list[len-1],此时list中子序列长度为1到len的对应的最右端最小值不变并新增长度为len+1的子序列最右端的最小值为nums[i],时间复杂度O(1);
2. if(nums[i]<=list[len-1])此时我们可以在0到len-1范围内找到k,list[k]为>=nums[i]的最小值,由于list单调递增所以我们可以使用二分搜索在O(logn)的时间复杂度内找到k。
1. 对于0<=j<k,list[j]<nums[i]恒成立对应list[j]的值不需要更新
2. 对于list[k]其值更新为nums[i],因为原本list[k]对应的子序列的倒数第二项的值可以=list[k-1]<nums[i]。
3. 对于k<j<=len-1,对应的list[j]不需要更新因为这些list[j]对应的子序列的倒数第二项的值>nums[i];
3. 综上算法时间复杂度为O(nlogn),空间复杂度为O(n),需要O(n)的空间保存list。
代码如下
Java
```java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if(n==0){return 0;}
List<Integer> list=new ArrayList<>();
list.add(nums[0]);
for (int i = 1; i < n; ++i) {
if (nums[i] > list.get(list.size()-1)) {
list.add(nums[i]);
} else {
int k=binarySearch(list,nums[i]);
list.set(k,nums[i]);
}
}
return list.size();
}
int binarySearch(List<Integer>list, int num){
int len=list.size();
int l=0,r=len-1,ans=len-1;
while(l<=r){
int mid=l+(r-l)/2;
if(list.get(mid)<num){
l=mid+1;
}else{
r=mid-1;
ans=mid;
}
}
return ans;
}
}
```
实际运行过程中list的长度不会超过n所以我们可以用数组来模拟list代码如下。
Java
```java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
if(n==0){return 0;}
//初始化listlen记录list长度
int[] list=new int[n];
int len=0;
//添加元素到list并更新len的值
list[len++]=nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > list[len-1]) {
list[len++]=nums[i];
} else {
int k=binarySearch(list,len,nums[i]);
list[k]=nums[i];
}
}
return len;
}
int binarySearch(int[] list,int len, int num){
int l=0,r=len-1,ans=len-1;
while(l<=r){
int mid=l+(r-l)/2;
if(list[mid]<num){
l=mid+1;
}else{
r=mid-1;
ans=mid;
}
}
return ans;
}
}
```

View File

@ -12,7 +12,7 @@
# 344.反转字符串 # 344.反转字符串
[力扣题目链接](https://leetcode-cn.com/problems/reverse-string/) https://leetcode-cn.com/problems/reverse-string/
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
@ -55,7 +55,7 @@
接下来再来讲一下如何解决反转字符串的问题。 接下来再来讲一下如何解决反转字符串的问题。
大家应该还记得,我们已经讲过了[206.反转链表](https://programmercarl.com/0206.翻转链表.html)。 大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)。
在反转链表中,使用了双指针的方法。 在反转链表中,使用了双指针的方法。
@ -63,7 +63,7 @@
因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。 因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。
如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html)[必须掌握的数组理论知识](https://programmercarl.com/数组理论基础.html)。 如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw)[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)。
对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。 对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
@ -162,21 +162,14 @@ class Solution:
Do not return anything, modify s in-place instead. Do not return anything, modify s in-place instead.
""" """
left, right = 0, len(s) - 1 left, right = 0, len(s) - 1
while(left < right):
# 该方法已经不需要判断奇偶数,经测试后时间空间复杂度比用 for i in range(right//2)更低
# 推荐该写法,更加通俗易懂
while left < right:
s[left], s[right] = s[right], s[left] s[left], s[right] = s[right], s[left]
left += 1 left += 1
right -= 1 right -= 1
# 下面的写法更加简洁,但是都是同样的算法
# class Solution:
# def reverseString(self, s: List[str]) -> None:
# """
# Do not return anything, modify s in-place instead.
# """
# 不需要判别是偶数个还是奇数个序列,因为奇数个的时候,中间那个不需要交换就可
# for i in range(len(s)//2):
# s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
# return s
``` ```
Go Go

View File

@ -14,7 +14,7 @@
## 349. 两个数组的交集 ## 349. 两个数组的交集
[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/) https://leetcode-cn.com/problems/intersection-of-two-arrays/
题意:给定两个数组,编写一个函数来计算它们的交集。 题意:给定两个数组,编写一个函数来计算它们的交集。
@ -32,7 +32,7 @@
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。 这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html) 那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)
但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。** 但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。**
@ -143,6 +143,26 @@ func intersection(nums1 []int, nums2 []int) []int {
return res return res
} }
``` ```
```golang
//优化版利用set减少count统计
func intersection(nums1 []int, nums2 []int) []int {
set:=make(map[int]struct{},0)
res:=make([]int,0)
for _,v:=range nums1{
if _,ok:=set[v];!ok{
set[v]=struct{}{}
}
}
for _,v:=range nums2{
//如果存在于上一个数组中则加入结果集并清空该set值
if _,ok:=set[v];ok{
res=append(res,v)
delete(set, v)
}
}
return res
}
```
javaScript: javaScript:

View File

@ -12,7 +12,7 @@
# 541. 反转字符串II # 541. 反转字符串II
[力扣题目链接](https://leetcode-cn.com/problems/reverse-string-ii/) https://leetcode-cn.com/problems/reverse-string-ii/
给定一个字符串 s 和一个整数 k你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 给定一个字符串 s 和一个整数 k你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
@ -65,7 +65,7 @@ public:
}; };
``` ```
那么我们也可以实现自己的reverse函数其实和题目[344. 反转字符串](https://programmercarl.com/0344.反转字符串.html)道理是一样的。 那么我们也可以实现自己的reverse函数其实和题目[344. 反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)道理是一样的。
下面我实现的reverse函数区间是左闭右闭区间代码如下 下面我实现的reverse函数区间是左闭右闭区间代码如下
@ -155,34 +155,27 @@ class Solution {
Python Python
```python ```python
class Solution:
class Solution(object): def reverseStr(self, s: str, k: int) -> str:
def reverseStr(self, s, k):
""" """
:type s: str 1. 使用range(start, end, step)来确定需要调换的初始位置
:type k: int 2. 对于字符串s = 'abc'如果使用s[0:999] ===> 'abc'。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理。
:rtype: str 3. 用切片整体替换,而不是一个个替换.
""" """
from functools import reduce def reverse_substring(text):
# turn s into a list left, right = 0, len(text) - 1
s = list(s)
# another way to simply use a[::-1], but i feel this is easier to understand
def reverse(s):
left, right = 0, len(s) - 1
while left < right: while left < right:
s[left], s[right] = s[right], s[left] text[left], text[right] = text[right], text[left]
left += 1 left += 1
right -= 1 right -= 1
return s return text
# make sure we reverse each 2k elements res = list(s)
for i in range(0, len(s), 2*k):
s[i:(i+k)] = reverse(s[i:(i+k)]) for cur in range(0, len(s), 2 * k):
res[cur: cur + k] = reverse_substring(res[cur: cur + k])
# combine list into str.
return reduce(lambda a, b: a+b, s)
return ''.join(res)
``` ```

View File

@ -10,7 +10,7 @@
# 1002. 查找常用字符 # 1002. 查找常用字符
[力扣题目链接](https://leetcode-cn.com/problems/find-common-characters/) https://leetcode-cn.com/problems/find-common-characters/
给定仅有小写字母组成的字符串数组 A返回列表中的每个字符串中都显示的全部字符包括重复字符组成的列表。例如如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。 给定仅有小写字母组成的字符串数组 A返回列表中的每个字符串中都显示的全部字符包括重复字符组成的列表。例如如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
@ -23,7 +23,7 @@
【示例二】 【示例二】
输入:["cool","lock","cook"] 输入:["cool","lock","cook"]
输出:["c","o"] 输出:["c","o"]
 
# 思路 # 思路
@ -40,9 +40,9 @@
可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。 可以看出这是指数级别的时间复杂度,非常高,而且代码实现也不容易,因为要统计 重复的字符,还要适当的替换或者去重。
那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。 那我们还是哈希法吧。如果对哈希法不了解,可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)。
如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://programmercarl.com/0242.有效的字母异位词.html)。 如果对用数组来做哈希法不了解的话,可以看这篇:[把数组当做哈希表来用,很巧妙!](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)。
了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。 了解了哈希法,理解了数组在哈希法中的应用之后,可以来看解题思路了。
@ -233,7 +233,41 @@ var commonChars = function (words) {
return res return res
}; };
``` ```
GO
```golang
func commonChars(words []string) []string {
length:=len(words)
fre:=make([][]int,0)//统计每个字符串的词频
res:=make([]string,0)
//统计词频
for i:=0;i<length;i++{
var row [26]int//存放该字符串的词频
for j:=0;j<len(words[i]);j++{
row[words[i][j]-97]++
}
fre=append(fre,row[:])
}
//查找一列的最小值
for j:=0;j<len(fre[0]);j++{
pre:=fre[0][j]
for i:=0;i<len(fre);i++{
pre=min(pre,fre[i][j])
}
//将该字符添加到结果集(按照次数)
tmpString:=string(j+97)
for i:=0;i<pre;i++{
res=append(res,tmpString)
}
}
return res
}
func min(a,b int)int{
if a>b{
return b
}
return a
}
```
----------------------- -----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -13,7 +13,7 @@
# 1047. 删除字符串中的所有相邻重复项 # 1047. 删除字符串中的所有相邻重复项
[力扣题目链接](https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/) https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/
给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母并删除它们。 给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母并删除它们。
@ -26,7 +26,7 @@
* 输入:"abbaca" * 输入:"abbaca"
* 输出:"ca" * 输出:"ca"
* 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。 * 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
 
提示: 提示:
* 1 <= S.length <= 20000 * 1 <= S.length <= 20000
@ -197,15 +197,38 @@ class Solution {
Python Python
```python3 ```python3
# 方法一,使用栈,推荐!
class Solution: class Solution:
def removeDuplicates(self, s: str) -> str: def removeDuplicates(self, s: str) -> str:
t = list() res = list()
for i in s: for item in s:
if t and t[-1] == i: if res and res[-1] == item:
t.pop(-1) res.pop()
else: else:
t.append(i) res.append(item)
return "".join(t) # 字符串拼接 return "".join(res) # 字符串拼接
```
```python3
# 方法二,使用双指针模拟栈,如果不让用栈可以作为备选方法。
class Solution:
def removeDuplicates(self, s: str) -> str:
res = list(s)
slow = fast = 0
length = len(res)
while fast < length:
# 如果一样直接换不一样会把后面的填在slow的位置
res[slow] = res[fast]
# 如果发现和前一个一样,就退一格指针
if slow > 0 and res[slow] == res[slow - 1]:
slow -= 1
else:
slow += 1
fast += 1
return ''.join(res[0: slow])
``` ```
Go Go

View File

@ -11,11 +11,11 @@
> 补充一波 > 补充一波
昨天的总结篇中[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg),有两处问题需要说明一波。 昨天的总结篇中[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://programmercarl.com/周总结/20201003二叉树周末总结.html),有两处问题需要说明一波。
## 求相同的树 ## 求相同的树
[还在玩耍的你,该总结啦!(本周小结之二叉树)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg)中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。 [还在玩耍的你,该总结啦!(本周小结之二叉树)](https://programmercarl.com/周总结/20201003二叉树周末总结.html)中求100.相同的树的代码中,我笔误贴出了 求对称树的代码了,细心的同学应该都发现了。
那么如下我再给出求100. 相同的树 的代码,如下: 那么如下我再给出求100. 相同的树 的代码,如下:
@ -42,13 +42,13 @@ public:
}; };
``` ```
以上的代码相对于:[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg) 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。 以上的代码相对于:[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html) 仅仅修改了变量的名字(为了符合判断相同树的语境)和 遍历的顺序。
大家应该会体会到:**认清[判断对称树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。** 大家应该会体会到:**认清[判断对称树](https://programmercarl.com/0101.对称二叉树.html)本质之后, 对称树的代码 稍作修改 就可以直接用来AC 100.相同的树。**
## 递归中隐藏着回溯 ## 递归中隐藏着回溯
在[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的提现了出来。 在[二叉树:找我的所有路径?](https://programmercarl.com/0257.二叉树的所有路径.html)中我强调了本题其实是用到了回溯的,并且给出了第一个版本的代码,把回溯的过程充分的提现了出来。
如下的代码充分的体现出回溯:(257. 二叉树的所有路径) 如下的代码充分的体现出回溯:(257. 二叉树的所有路径)
@ -166,7 +166,7 @@ if (cur->right) {
**大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的因为并有没有改变path的数值执行完递归函数之后path依然是之前的数值相当于回溯了** **大家应该可以感受出来,如果把 `path + "->"`作为函数参数就是可以的因为并有没有改变path的数值执行完递归函数之后path依然是之前的数值相当于回溯了**
如果有点遗忘了,建议把这篇[二叉树:找我的所有路径?](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)在仔细看一下,然后再看这里的总结,相信会豁然开朗。 如果有点遗忘了,建议把这篇[二叉树:找我的所有路径?](https://programmercarl.com/0257.二叉树的所有路径.html)在仔细看一下,然后再看这里的总结,相信会豁然开朗。
这里我尽量把逻辑的每一个细节都抠出来展现了,希望对大家有所帮助! 这里我尽量把逻辑的每一个细节都抠出来展现了,希望对大家有所帮助!

View File

@ -22,105 +22,106 @@
## 二叉树的理论基础 ## 二叉树的理论基础
* [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A):二叉树的种类、存储方式、遍历方式、定义方式 * [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html):二叉树的种类、存储方式、遍历方式、定义方式
## 二叉树的遍历方式 ## 二叉树的遍历方式
* 深度优先遍历 * 深度优先遍历
* [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA):递归三部曲初次亮相 * [二叉树:前中后序递归法](https://programmercarl.com/二叉树的递归遍历.html):递归三部曲初次亮相
* [二叉树:前中后序迭代法(一)](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg):通过栈模拟递归 * [二叉树:前中后序迭代法(一)](https://programmercarl.com/二叉树的迭代遍历.html):通过栈模拟递归
* [二叉树:前中后序迭代法(二)统一风格](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg) * [二叉树:前中后序迭代法(二)统一风格](https://programmercarl.com/二叉树的统一迭代法.html)
* 广度优先遍历 * 广度优先遍历
* [二叉树的层序遍历](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog):通过队列模拟 * [二叉树的层序遍历](https://programmercarl.com/0102.二叉树的层序遍历.html):通过队列模拟
## 求二叉树的属性 ## 求二叉树的属性
* [二叉树:是否对称](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg) * [二叉树:是否对称](https://programmercarl.com/0101.对称二叉树.html)
* 递归:后序,比较的是根节点的左子树与右子树是不是相互翻转 * 递归:后序,比较的是根节点的左子树与右子树是不是相互翻转
* 迭代:使用队列/栈将两个节点顺序放入容器中进行比较 * 迭代:使用队列/栈将两个节点顺序放入容器中进行比较
* [二叉树:求最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg) * [二叉树:求最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)
* 递归:后序,求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度 * 递归:后序,求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度
* 迭代:层序遍历 * 迭代:层序遍历
* [二叉树:求最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA) * [二叉树:求最小深度](https://programmercarl.com/0111.二叉树的最小深度.html)
* 递归:后序,求根节点最小高度就是最小深度,注意最小深度的定义 * 递归:后序,求根节点最小高度就是最小深度,注意最小深度的定义
* 迭代:层序遍历 * 迭代:层序遍历
* [二叉树:求有多少个节点](https://mp.weixin.qq.com/s/2_eAjzw-D0va9y4RJgSmXw) * [二叉树:求有多少个节点](https://programmercarl.com/0222.完全二叉树的节点个数.html)
* 递归:后序,通过递归函数的返回值计算节点数量 * 递归:后序,通过递归函数的返回值计算节点数量
* 迭代:层序遍历 * 迭代:层序遍历
* [二叉树:是否平衡](https://mp.weixin.qq.com/s/isUS-0HDYknmC0Rr4R8mww) * [二叉树:是否平衡](https://programmercarl.com/0110.平衡二叉树.html)
* 递归:后序,注意后序求高度和前序求深度,递归过程判断高度差 * 递归:后序,注意后序求高度和前序求深度,递归过程判断高度差
* 迭代:效率很低,不推荐 * 迭代:效率很低,不推荐
* [二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA) * [二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)
* 递归:前序,方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径 * 递归:前序,方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径
* 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径 * 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径
* [二叉树:递归中如何隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA) * [二叉树:递归中如何隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)
* 详解[二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)中递归如何隐藏着回溯 * 详解[二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)中递归如何隐藏着回溯
* [二叉树:求左叶子之和](https://mp.weixin.qq.com/s/gBAgmmFielojU5Wx3wqFTA) * [二叉树:求左叶子之和](https://programmercarl.com/0404.左叶子之和.html)
* 递归:后序,必须三层约束条件,才能判断是否是左叶子。 * 递归:后序,必须三层约束条件,才能判断是否是左叶子。
* 迭代:直接模拟后序遍历 * 迭代:直接模拟后序遍历
* [二叉树:求左下角的值](https://mp.weixin.qq.com/s/MH2gbLvzQ91jHPKqiub0Nw) * [二叉树:求左下角的值](https://programmercarl.com/0513.找树左下角的值.html)
* 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。 * 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。
* 迭代:层序遍历找最后一行最左边 * 迭代:层序遍历找最后一行最左边
* [二叉树:求路径总和](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) * [二叉树:求路径总和](https://programmercarl.com/0112.路径总和.html)
* 递归顺序无所谓递归函数返回值为bool类型是为了搜索一条边没有返回值是搜索整棵树。 * 递归顺序无所谓递归函数返回值为bool类型是为了搜索一条边没有返回值是搜索整棵树。
* 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和 * 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和
## 二叉树的修改与构造 ## 二叉树的修改与构造
* [翻转二叉树](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg) * [翻转二叉树](https://programmercarl.com/0226.翻转二叉树.html)
* 递归:前序,交换左右孩子 * 递归:前序,交换左右孩子
* 迭代:直接模拟前序遍历 * 迭代:直接模拟前序遍历
* [构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) * [构造二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)
* 递归:前序,重点在于找分割点,分左右区间构造 * 递归:前序,重点在于找分割点,分左右区间构造
* 迭代:比较复杂,意义不大 * 迭代:比较复杂,意义不大
* [构造最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w) * [构造最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)
* 递归:前序,分割点为数组最大值,分左右区间构造 * 递归:前序,分割点为数组最大值,分左右区间构造
* 迭代:比较复杂,意义不大 * 迭代:比较复杂,意义不大
* [合并两个二叉树](https://mp.weixin.qq.com/s/3f5fbjOFaOX_4MXzZ97LsQ) * [合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html)
* 递归:前序,同时操作两个树的节点,注意合并的规则 * 递归:前序,同时操作两个树的节点,注意合并的规则
* 迭代:使用队列,类似层序遍历 * 迭代:使用队列,类似层序遍历
## 求二叉搜索树的属性 ## 求二叉搜索树的属性
* [二叉搜索树中的搜索](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg) * [二叉搜索树中的搜索](https://programmercarl.com/0700.二叉搜索树中的搜索.html)
* 递归:二叉搜索树的递归是有方向的 * 递归:二叉搜索树的递归是有方向的
* 迭代:因为有方向,所以迭代法很简单 * 迭代:因为有方向,所以迭代法很简单
* [是不是二叉搜索树](https://mp.weixin.qq.com/s/8odY9iUX5eSi0eRFSXFD4Q) * [是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)
* 递归:中序,相当于变成了判断一个序列是不是递增的 * 递归:中序,相当于变成了判断一个序列是不是递增的
* 迭代:模拟中序,逻辑相同 * 迭代:模拟中序,逻辑相同
* [求二叉搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ) * [求二叉搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)
* 递归:中序,双指针操作 * 递归:中序,双指针操作
* 迭代:模拟中序,逻辑相同 * 迭代:模拟中序,逻辑相同
* [求二叉搜索树的众数](https://mp.weixin.qq.com/s/KSAr6OVQIMC-uZ8MEAnGHg) * [求二叉搜索树的众数](https://programmercarl.com/0501.二叉搜索树中的众数.html)
* 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合 * 递归:中序,清空结果集的技巧,遍历一遍便可求众数集合
* 迭代:模拟中序,逻辑相同 * [二叉搜索树转成累加树](https://programmercarl.com/0538.把二叉搜索树转换为累加树.html)
* [二叉搜索树转成累加树](https://mp.weixin.qq.com/s/hZtJh4T5lIGBarY-lZJf6Q)
* 递归:中序,双指针操作累加 * 递归:中序,双指针操作累加
* 迭代:模拟中序,逻辑相同 * 迭代:模拟中序,逻辑相同
## 二叉树公共祖先问题 ## 二叉树公共祖先问题
* [二叉树的公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ) * [二叉树的公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)
* 递归:后序,回溯,找到左子树出现目标值,右子树节点目标值的节点。 * 递归:后序,回溯,找到左子树出现目标值,右子树节点目标值的节点。
* 迭代:不适合模拟回溯 * 迭代:不适合模拟回溯
* [二叉搜索树的公共祖先问题](https://mp.weixin.qq.com/s/Ja9dVw2QhBcg_vV-1fkiCg) * [二叉搜索树的公共祖先问题](https://programmercarl.com/0235.二叉搜索树的最近公共祖先.html)
* 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先 * 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先
* 迭代:按序遍历 * 迭代:按序遍历
## 二叉搜索树的修改与构造 ## 二叉搜索树的修改与构造
* [二叉搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA) * [二叉搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)
* 递归:顺序无所谓,通过递归函数返回值添加节点 * 递归:顺序无所谓,通过递归函数返回值添加节点
* 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作 * 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作
* [二叉搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw) * [二叉搜索树中的删除操作](https://programmercarl.com/0450.删除二叉搜索树中的节点.html)
* 递归:前序,想清楚删除非叶子节点的情况 * 递归:前序,想清楚删除非叶子节点的情况
* 迭代:有序遍历,较复杂 * 迭代:有序遍历,较复杂
* [修剪二叉搜索树](https://mp.weixin.qq.com/s/QzmGfYUMUWGkbRj7-ozHoQ) * [修剪二叉搜索树](https://programmercarl.com/0669.修剪二叉搜索树.html)
* 递归:前序,通过递归函数返回值删除节点 * 递归:前序,通过递归函数返回值删除节点
* 迭代:有序遍历,较复杂 * 迭代:有序遍历,较复杂
* [构造二叉搜索树](https://mp.weixin.qq.com/s/sy3ygnouaZVJs8lhFgl9mw) * [构造二叉搜索树](https://programmercarl.com/0108.将有序数组转换为二叉搜索树.html)
* 递归:前序,数组中间节点分割 * 递归:前序,数组中间节点分割
* 迭代:较复杂,通过三个队列来模拟 * 迭代:较复杂,通过三个队列来模拟
@ -130,10 +131,10 @@
**每周小结都会对大家的疑问做统一解答,并且对每周的内容进行拓展和补充,所以一定要看,将细碎知识点一网打尽!** **每周小结都会对大家的疑问做统一解答,并且对每周的内容进行拓展和补充,所以一定要看,将细碎知识点一网打尽!**
* [本周小结!(二叉树系列一)](https://mp.weixin.qq.com/s/JWmTeC7aKbBfGx4TY6uwuQ) * [本周小结!(二叉树系列一)](https://programmercarl.com/周总结/20200927二叉树周末总结.html)
* [本周小结!(二叉树系列二)](https://mp.weixin.qq.com/s/QMBUTYnoaNfsVHlUADEzKg) * [本周小结!(二叉树系列二)](https://programmercarl.com/周总结/20201003二叉树周末总结.html)
* [本周小结!(二叉树系列三)](https://mp.weixin.qq.com/s/JLLpx3a_8jurXcz6ovgxtg) * [本周小结!(二叉树系列三)](https://programmercarl.com/周总结/20201010二叉树周末总结.html)
* [本周小结!(二叉树系列四)](https://mp.weixin.qq.com/s/CbdtOTP0N-HIP7DR203tSg) * [本周小结!(二叉树系列四)](https://programmercarl.com/周总结/20201017二叉树周末总结.html)
## 最后总结 ## 最后总结
@ -145,7 +146,7 @@
* 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。 * 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。
注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序, [二叉树:找所有路径](https://mp.weixin.qq.com/s/Osw4LQD2xVUnCJ-9jrYxJA)也用了前序,这是为了方便让父节点指向子节点。 注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,[二叉树:找所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)也用了前序,这是为了方便让父节点指向子节点。
所以求普通二叉树的属性还是要具体问题具体分析。 所以求普通二叉树的属性还是要具体问题具体分析。

View File

@ -12,9 +12,9 @@
> 统一写法是一种什么感觉 > 统一写法是一种什么感觉
此时我们在[二叉树一入递归深似海从此offer是路人](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)中用递归的方式,实现了二叉树前中后序的遍历。 此时我们在[二叉树一入递归深似海从此offer是路人](https://programmercarl.com/二叉树的递归遍历.html)中用递归的方式,实现了二叉树前中后序的遍历。
在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中用栈实现了二叉树前后中序的迭代遍历(非递归)。 在[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中用栈实现了二叉树前后中序的迭代遍历(非递归)。
之后我们发现**迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。** 之后我们发现**迭代法实现的先中后序,其实风格也不是那么统一,除了先序和后序,有关联,中序完全就是另一个风格了,一会用栈遍历,一会又用指针来遍历。**
@ -24,7 +24,7 @@
**重头戏来了,接下来介绍一下统一写法。** **重头戏来了,接下来介绍一下统一写法。**
我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。 我们以中序遍历为例,在[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中提到说使用栈的话,**无法同时解决访问节点(遍历节点)和处理节点(将元素放进结果集)不一致的情况**。
**那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。** **那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。**

View File

@ -19,7 +19,7 @@
为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢? 为什么可以用迭代法(非递归的方式)来实现二叉树的前后中序遍历呢?
我们在[栈与队列:匹配问题都是栈的强项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。 我们在[栈与队列:匹配问题都是栈的强项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中提到了,**递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中**,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。 此时大家应该知道我们用栈也可以是实现二叉树的前后中序遍历了。

View File

@ -10,16 +10,16 @@
![股票问题总结](https://code-thinking.cdn.bcebos.com/pics/%E8%82%A1%E7%A5%A8%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93.jpg) ![股票问题总结](https://code-thinking.cdn.bcebos.com/pics/%E8%82%A1%E7%A5%A8%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93.jpg)
* [动态规划121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) * [动态规划121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)
* [动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) * [动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)
* [动态规划123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg) * [动态规划123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)
* [动态规划188.买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) * [动态规划188.买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html)
* [动态规划309.最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) * [动态规划309.最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)
* [动态规划714.买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) * [动态规划714.买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html)
## 卖股票的最佳时机 ## 卖股票的最佳时机
[动态规划121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)**股票只能买卖一次,问最大利润**。 [动态规划121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)**股票只能买卖一次,问最大利润**。
【贪心解法】 【贪心解法】
@ -103,7 +103,7 @@ public:
## 买卖股票的最佳时机II ## 买卖股票的最佳时机II
[动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)可以多次买卖股票,问最大收益。 [动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)可以多次买卖股票,问最大收益。
【贪心解法】 【贪心解法】
@ -138,9 +138,9 @@ dp数组定义
* 第i-1天就持有股票那么就保持现状所得现金就是昨天持有股票的所得现金 即dp[i - 1][0] * 第i-1天就持有股票那么就保持现状所得现金就是昨天持有股票的所得现金 即dp[i - 1][0]
* 第i天买入股票所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即dp[i - 1][1] - prices[i] * 第i天买入股票所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即dp[i - 1][1] - prices[i]
**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)唯一不同的地方就是推导dp[i][0]的时候第i天买入股票的情况** **注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)唯一不同的地方就是推导dp[i][0]的时候第i天买入股票的情况**
在[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)中因为股票全程只能买卖一次所以如果买入股票那么第i天持有股票即dp[i][0]一定就是 -prices[i]。 在[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)中因为股票全程只能买卖一次所以如果买入股票那么第i天持有股票即dp[i][0]一定就是 -prices[i]。
而本题因为一只股票可以买卖多次所以当第i天买入股票的时候所持有的现金可能有之前买卖过的利润。 而本题因为一只股票可以买卖多次所以当第i天买入股票的时候所持有的现金可能有之前买卖过的利润。
@ -169,7 +169,7 @@ public:
## 买卖股票的最佳时机III ## 买卖股票的最佳时机III
[动态规划123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)最多买卖两次,问最大收益。 [动态规划123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)最多买卖两次,问最大收益。
【动态规划】 【动态规划】
@ -257,7 +257,7 @@ public:
## 买卖股票的最佳时机IV ## 买卖股票的最佳时机IV
[动态规划188.买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) 最多买卖k笔交易问最大收益。 [动态规划188.买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html) 最多买卖k笔交易问最大收益。
使用二维数组 dp[i][j] 第i天的状态为j所剩下的最大现金是dp[i][j] 使用二维数组 dp[i][j] 第i天的状态为j所剩下的最大现金是dp[i][j]
@ -325,12 +325,12 @@ public:
## 最佳买卖股票时机含冷冻期 ## 最佳买卖股票时机含冷冻期
[动态规划309.最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) 可以多次买卖但每次卖出有冷冻期1天。 [动态规划309.最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)可以多次买卖但每次卖出有冷冻期1天。
相对于[动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题加上了一个冷冻期。 相对于[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html),本题加上了一个冷冻期。
在[动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。本题则可以花费为四个状态 在[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。本题则可以花费为四个状态
dp[i][j]第i天状态为j所剩的最多现金为dp[i][j]。 dp[i][j]第i天状态为j所剩的最多现金为dp[i][j]。
@ -408,10 +408,10 @@ public:
## 买卖股票的最佳时机含手续费 ## 买卖股票的最佳时机含手续费
[动态规划714.买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) 可以多次买卖,但每次有手续费。 [动态规划714.买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html) 可以多次买卖,但每次有手续费。
相对于[动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。 相对于[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html),本题只需要在计算卖出操作的时候减去手续费就可以了,代码几乎是一样的。
唯一差别在于递推公式部分,所以本篇也就不按照动规五部曲详细讲解了,主要讲解一下递推公式部分。 唯一差别在于递推公式部分,所以本篇也就不按照动规五部曲详细讲解了,主要讲解一下递推公式部分。
@ -435,7 +435,7 @@ dp[i][1] 表示第i天不持有股票所得最多现金
所以dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee); 所以dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
**本题和[动态规划122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w)的区别就是这里需要多一个减去手续费的操作** **本题和[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)的区别就是这里需要多一个减去手续费的操作**
以上分析完毕,代码如下: 以上分析完毕,代码如下:

View File

@ -10,7 +10,7 @@
如今动态规划已经讲解了42道经典题目共50篇文章是时候做一篇总结了。 如今动态规划已经讲解了42道经典题目共50篇文章是时候做一篇总结了。
关于动态规划,在专题第一篇[关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag)就说了动规五部曲,**而且强调了五部对解动规题目至关重要!** 关于动态规划,在专题第一篇[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)就说了动规五部曲,**而且强调了五部对解动规题目至关重要!**
这是Carl做过一百多道动规题目总结出来的经验结晶啊如果大家跟着「代码随想哦」刷过动规专题一定会对这动规五部曲的作用感受极其深刻。 这是Carl做过一百多道动规题目总结出来的经验结晶啊如果大家跟着「代码随想哦」刷过动规专题一定会对这动规五部曲的作用感受极其深刻。
@ -35,7 +35,7 @@
动规五部曲里,哪一部没想清楚,这道题目基本就做不出来,即使做出来了也没有想清楚,而是朦朦胧胧的就把题目过了。 动规五部曲里,哪一部没想清楚,这道题目基本就做不出来,即使做出来了也没有想清楚,而是朦朦胧胧的就把题目过了。
* 如果想不清楚dp数组的具体含义递归公式从何谈起甚至初始化的时候就写错了。 * 如果想不清楚dp数组的具体含义递归公式从何谈起甚至初始化的时候就写错了。
* 例如[动态规划:不同路径还不够,要有障碍!](https://mp.weixin.qq.com/s/lhqF0O4le9-wvalptOVOww) 在这道题目中,初始化才是重头戏 * 例如[动态规划:不同路径还不够,要有障碍!](https://programmercarl.com/0063.不同路径II.html) 在这道题目中,初始化才是重头戏
* 如果看过背包系列特别是完全背包那么两层for循环先后顺序绝对可以搞懵很多人反而递归公式是简单的。 * 如果看过背包系列特别是完全背包那么两层for循环先后顺序绝对可以搞懵很多人反而递归公式是简单的。
* 至于推导dp数组的重要性动规专题里几乎每篇Carl都反复强调当程序结果不对的时候一定要自己推导公式看看和程序打印的日志是否一样。 * 至于推导dp数组的重要性动规专题里几乎每篇Carl都反复强调当程序结果不对的时候一定要自己推导公式看看和程序打印的日志是否一样。
@ -43,72 +43,72 @@
## 动划基础 ## 动划基础
* [关于动态规划,你该了解这些!](https://mp.weixin.qq.com/s/ocZwfPlCWrJtVGACqFNAag) * [关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)
* [动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w) * [动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)
* [动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw) * [动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html)
* [动态规划:使用最小花费爬楼梯](https://mp.weixin.qq.com/s/djZB9gkyLFAKcQcSvKDorA) * [动态规划:使用最小花费爬楼梯](https://programmercarl.com/0746.使用最小花费爬楼梯.html)
* [动态规划:不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A) * [动态规划:不同路径](https://programmercarl.com/0062.不同路径.html)
* [动态规划:不同路径还不够,要有障碍!](https://mp.weixin.qq.com/s/lhqF0O4le9-wvalptOVOww) * [动态规划:不同路径还不够,要有障碍!](https://programmercarl.com/0063.不同路径II.html)
* [动态规划:整数拆分,你要怎么拆?](https://mp.weixin.qq.com/s/cVbyHrsWH_Rfzlj-ESr01A) * [动态规划:整数拆分,你要怎么拆?](https://programmercarl.com/0343.整数拆分.html)
* [动态规划:不同的二叉搜索树](https://mp.weixin.qq.com/s/8VE8pDrGxTf8NEVYBDwONw) * [动态规划:不同的二叉搜索树](https://programmercarl.com/0096.不同的二叉搜索树.html)
## 背包问题系列 ## 背包问题系列
<img src='https://code-thinking.cdn.bcebos.com/pics/动态规划-背包问题总结.png' width=500 alt='背包问题大纲'> </img></div> <img src='https://code-thinking.cdn.bcebos.com/pics/动态规划-背包问题总结.png' width=500 alt='背包问题大纲'> </img></div>
* [动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) * [动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)
* [动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) * [动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)
* [动态规划分割等和子集可以用01背包](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ) * [动态规划分割等和子集可以用01背包](https://programmercarl.com/0416.分割等和子集.html)
* [动态规划:最后一块石头的重量 II](https://mp.weixin.qq.com/s/WbwAo3jaUaNJjvhHgq0BGg) * [动态规划:最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html)
* [动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) * [动态规划:目标和!](https://programmercarl.com/0494.目标和.html)
* [动态规划:一和零!](https://mp.weixin.qq.com/s/x-u3Dsp76DlYqtCe0xEKJw) * [动态规划:一和零!](https://programmercarl.com/0474.一和零.html)
* [动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw) * [动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)
* [动态规划:给你一些零钱,你要怎么凑?](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) * [动态规划:给你一些零钱,你要怎么凑?](https://programmercarl.com/0518.零钱兑换II.html)
* [动态规划Carl称它为排列总和](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA) * [动态规划Carl称它为排列总和](https://programmercarl.com/0377.组合总和Ⅳ.html)
* [动态规划:以前我没得选,现在我选择再爬一次!](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) * [动态规划:以前我没得选,现在我选择再爬一次!](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
* [动态规划: 给我个机会,我再兑换一次零钱](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ) * [动态规划: 给我个机会,我再兑换一次零钱](https://programmercarl.com/0322.零钱兑换.html)
* [动态规划:一样的套路,再求一次完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) * [动态规划:一样的套路,再求一次完全平方数](https://programmercarl.com/0279.完全平方数.html)
* [动态规划:单词拆分](https://mp.weixin.qq.com/s/3Spx1B6MbIYjS8YkVbByzA) * [动态规划:单词拆分](https://programmercarl.com/0139.单词拆分.html)
* [动态规划:关于多重背包,你该了解这些!](https://mp.weixin.qq.com/s/b-UUUmbvG7URWyCjQkiuuQ) * [动态规划:关于多重背包,你该了解这些!](https://programmercarl.com/背包问题理论基础多重背包.html)
* [听说背包问题很难? 这篇总结篇来拯救你了](https://mp.weixin.qq.com/s/ZOehl3U1mDiyOQjFG1wNJA) * [听说背包问题很难? 这篇总结篇来拯救你了](https://programmercarl.com/背包总结篇.html)
## 打家劫舍系列 ## 打家劫舍系列
* [动态规划:开始打家劫舍!](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw) * [动态规划:开始打家劫舍!](https://programmercarl.com/0198.打家劫舍.html)
* [动态规划:继续打家劫舍!](https://mp.weixin.qq.com/s/kKPx4HpH3RArbRcxAVHbeQ) * [动态规划:继续打家劫舍!](https://programmercarl.com/0213.打家劫舍II.html)
* [动态规划:还要打家劫舍!](https://mp.weixin.qq.com/s/BOJ1lHsxbQxUZffXlgglEQ) * [动态规划:还要打家劫舍!](https://programmercarl.com/0337.打家劫舍III.html)
## 股票系列 ## 股票系列
<img src='https://code-thinking.cdn.bcebos.com/pics/股票问题总结.jpg' width=500 alt='股票问题总结'> </img></div> <img src='https://code-thinking.cdn.bcebos.com/pics/股票问题总结.jpg' width=500 alt='股票问题总结'> </img></div>
* [动态规划:买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) * [动态规划:买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)
* [动态规划:本周我们都讲了这些(系列六)](https://mp.weixin.qq.com/s/GVu-6eF0iNkpVDKRXTPOTA) * [动态规划:本周我们都讲了这些(系列六)](https://programmercarl.com/周总结/20210225动规周末总结.html)
* [动态规划买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) * [动态规划买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)
* [动态规划买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg) * [动态规划买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)
* [动态规划买卖股票的最佳时机IV](https://mp.weixin.qq.com/s/jtxZJWAo2y5sUsW647Z5cw) * [动态规划买卖股票的最佳时机IV](https://programmercarl.com/0188.买卖股票的最佳时机IV.html)
* [动态规划:最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/TczJGFAPnkjH9ET8kwH1OA) * [动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)
* [动态规划:本周我们都讲了这些(系列七)](https://mp.weixin.qq.com/s/vdzDlrEvhXWRzblTnOnzKg) * [动态规划:本周我们都讲了这些(系列七)](https://programmercarl.com/周总结/20210304动规周末总结.html)
* [动态规划:买卖股票的最佳时机含手续费](https://mp.weixin.qq.com/s/2Cd_uINjerZ25VHH0K2IBQ) * [动态规划:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费(动态规划).html)
* [动态规划:股票系列总结篇](https://mp.weixin.qq.com/s/sC5XyEtDQWkonKnbCvZhDw) * [动态规划:股票系列总结篇](https://programmercarl.com/动态规划-股票问题总结篇.html)
## 子序列系列 ## 子序列系列
<img src='https://code-thinking.cdn.bcebos.com/pics/动态规划-子序列问题总结.jpg' width=500 alt=''> </img></div> <img src='https://code-thinking.cdn.bcebos.com/pics/动态规划-子序列问题总结.jpg' width=500 alt=''> </img></div>
* [动态规划:最长递增子序列](https://mp.weixin.qq.com/s/f8nLO3JGfgriXep_gJQpqQ) * [动态规划:最长递增子序列](https://programmercarl.com/0300.最长上升子序列.html)
* [动态规划:最长连续递增序列](https://mp.weixin.qq.com/s/c0Nn0TtjkTISVdqRsyMmyA) * [动态规划:最长连续递增序列](https://programmercarl.com/0674.最长连续递增序列.html)
* [动态规划:最长重复子数组](https://mp.weixin.qq.com/s/U5WaWqBwdoxzQDotOdWqZg) * [动态规划:最长重复子数组](https://programmercarl.com/0718.最长重复子数组.html)
* [动态规划:最长公共子序列](https://mp.weixin.qq.com/s/Qq0q4HaE4TyasCTj2WGFOg) * [动态规划:最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)
* [动态规划:不相交的线](https://mp.weixin.qq.com/s/krfYzSYEO8jIoVfyHzR0rw) * [动态规划:不相交的线](https://programmercarl.com/1035.不相交的线.html)
* [动态规划:最大子序和](https://mp.weixin.qq.com/s/2Xtyi2L4r8sM-BcxgUKmcA) * [动态规划:最大子序和](https://programmercarl.com/0053.最大子序和(动态规划).html)
* [动态规划:判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng) * [动态规划:判断子序列](https://programmercarl.com/0392.判断子序列.html)
* [动态规划:不同的子序列](https://mp.weixin.qq.com/s/1SULY2XVSROtk_hsoVLu8A) * [动态规划:不同的子序列](https://programmercarl.com/0115.不同的子序列.html)
* [动态规划:两个字符串的删除操作](https://mp.weixin.qq.com/s/a8BerpqSf76DCqkPDJrpYg) * [动态规划:两个字符串的删除操作](https://programmercarl.com/0583.两个字符串的删除操作.html)
* [动态规划:编辑距离](https://mp.weixin.qq.com/s/8aG71XjSgZG6kZbiAdkJnQ) * [动态规划:编辑距离](https://programmercarl.com/0072.编辑距离.html)
* [为了绝杀编辑距离,我做了三步铺垫,你都知道么?](https://mp.weixin.qq.com/s/kbs4kCUzg8gPFttF9H3Yyw) * [为了绝杀编辑距离,我做了三步铺垫,你都知道么?](https://programmercarl.com/为了绝杀编辑距离,卡尔做了三步铺垫.html)
* [动态规划:回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw) * [动态规划:回文子串](https://programmercarl.com/0647.回文子串.html)
* [动态规划:最长回文子序列](https://mp.weixin.qq.com/s/jbd3p4QPm5Kh1s2smTzWag) * [动态规划:最长回文子序列](https://programmercarl.com/0516.最长回文子序列.html)
## 动规结束语 ## 动规结束语

View File

@ -12,7 +12,7 @@
所以动态规划中每一个状态一定是由上一个状态推导出来的,**这一点就区分于贪心**,贪心没有状态推导,而是从局部直接选最优的, 所以动态规划中每一个状态一定是由上一个状态推导出来的,**这一点就区分于贪心**,贪心没有状态推导,而是从局部直接选最优的,
在[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中我举了一个背包问题的例子。 在[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中我举了一个背包问题的例子。
例如有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 例如有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。

View File

@ -30,30 +30,30 @@
## 背包递推公式 ## 背包递推公式
问能否能装满背包或者最多装多少dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); ,对应题目如下: 问能否能装满背包或者最多装多少dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]); ,对应题目如下:
* [动态规划416.分割等和子集](https://mp.weixin.qq.com/s/sYw3QtPPQ5HMZCJcT4EaLQ) * [动态规划416.分割等和子集](https://programmercarl.com/0416.分割等和子集.html)
* [动态规划1049.最后一块石头的重量 II](https://mp.weixin.qq.com/s/WbwAo3jaUaNJjvhHgq0BGg) * [动态规划1049.最后一块石头的重量 II](https://programmercarl.com/1049.最后一块石头的重量II.html)
问装满背包有几种方法dp[j] += dp[j - nums[i]] ,对应题目如下: 问装满背包有几种方法dp[j] += dp[j - nums[i]] ,对应题目如下:
* [动态规划494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) * [动态规划494.目标和](https://programmercarl.com/0494.目标和.html)
* [动态规划518. 零钱兑换 II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) * [动态规划518. 零钱兑换 II](https://programmercarl.com/0518.零钱兑换II.html)
* [动态规划377.组合总和Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA) * [动态规划377.组合总和Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)
* [动态规划70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) * [动态规划70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
问背包装满最大价值dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下: 问背包装满最大价值dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); ,对应题目如下:
* [动态规划474.一和零](https://mp.weixin.qq.com/s/x-u3Dsp76DlYqtCe0xEKJw) * [动态规划474.一和零](https://programmercarl.com/0474.一和零.html)
问装满背包所有物品的最小个数dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下: 问装满背包所有物品的最小个数dp[j] = min(dp[j - coins[i]] + 1, dp[j]); ,对应题目如下:
* [动态规划322.零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ) * [动态规划322.零钱兑换](https://programmercarl.com/0322.零钱兑换.html)
* [动态规划279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) * [动态规划279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
## 遍历顺序 ## 遍历顺序
### 01背包 ### 01背包
在[动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。 在[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)中我们讲解二维dp数组01背包先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。
和[动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量且第二层for循环是从大到小遍历。 和[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中我们讲解一维dp数组01背包只能先遍历物品再遍历背包容量且第二层for循环是从大到小遍历。
**一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的大家需要注意** **一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的大家需要注意**
@ -61,7 +61,7 @@
说完01背包再看看完全背包。 说完01背包再看看完全背包。
在[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)中讲解了纯完全背包的一维dp数组实现先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。 在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中讲解了纯完全背包的一维dp数组实现先遍历物品还是先遍历背包都是可以的且第二层for循环是从小到大遍历。
但是仅仅是纯完全背包的遍历顺序是这样的题目稍有变化两个for循环的先后顺序就不一样了。 但是仅仅是纯完全背包的遍历顺序是这样的题目稍有变化两个for循环的先后顺序就不一样了。
@ -71,12 +71,12 @@
相关题目如下: 相关题目如下:
* 求组合数:[动态规划518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) * 求组合数:[动态规划518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)
* 求排列数:[动态规划377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA) * 求排列数:[动态规划377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
如果求最小数那么两层for循环的先后顺序就无所谓了相关题目如下 如果求最小数那么两层for循环的先后顺序就无所谓了相关题目如下
* 求最小数:[动态规划322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)、[动态规划279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ) * 求最小数:[动态规划322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
**对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了** **对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了**
@ -88,7 +88,7 @@
**而且每一个点,我都给出了对应的力扣题目** **而且每一个点,我都给出了对应的力扣题目**
最后如果你想了解多重背包,可以看这篇[动态规划:关于多重背包,你该了解这些!](https://mp.weixin.qq.com/s/b-UUUmbvG7URWyCjQkiuuQ),力扣上还没有多重背包的题目,也不是面试考察的重点。 最后如果你想了解多重背包,可以看这篇[动态规划:关于多重背包,你该了解这些!](https://programmercarl.com/背包问题理论基础多重背包.html),力扣上还没有多重背包的题目,也不是面试考察的重点。
如果把我本篇总结出来的内容都掌握的话,可以说对背包问题理解的就很深刻了,用来对付面试中的背包问题绰绰有余! 如果把我本篇总结出来的内容都掌握的话,可以说对背包问题理解的就很深刻了,用来对付面试中的背包问题绰绰有余!

View File

@ -8,7 +8,7 @@
# 动态规划关于01背包问题你该了解这些滚动数组 # 动态规划关于01背包问题你该了解这些滚动数组
昨天[动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)中是用二维dp数组来讲解01背包。 昨天[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)中是用二维dp数组来讲解01背包。
今天我们就来说一说滚动数组其实在前面的题目中我们已经用到过滚动数组了就是把二维dp降为一维dp一些录友当时还表示比较困惑。 今天我们就来说一说滚动数组其实在前面的题目中我们已经用到过滚动数组了就是把二维dp降为一维dp一些录友当时还表示比较困惑。
@ -199,7 +199,7 @@ int main() {
大家可以发现其实信息量还是挺大的。 大家可以发现其实信息量还是挺大的。
如果把[动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)和本篇的内容都理解了后面我们在做01背包的题目就会发现非常简单了。 如果把[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)和本篇的内容都理解了后面我们在做01背包的题目就会发现非常简单了。
不用再凭感觉或者记忆去写背包,而是有自己的思考,了解其本质,代码的方方面面都在自己的掌控之中。 不用再凭感觉或者记忆去写背包,而是有自己的思考,了解其本质,代码的方方面面都在自己的掌控之中。

View File

@ -9,9 +9,9 @@
之前我们已经体统的讲解了01背包和完全背包如果没有看过的录友建议先把如下三篇文章仔细阅读一波。 之前我们已经体统的讲解了01背包和完全背包如果没有看过的录友建议先把如下三篇文章仔细阅读一波。
* [动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) * [动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)
* [动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) * [动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)
* [动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw) * [动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)
这次我们再来说一说多重背包 这次我们再来说一说多重背包

View File

@ -35,8 +35,8 @@
关于01背包我如下两篇已经进行深入分析了 关于01背包我如下两篇已经进行深入分析了
* [动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) * [动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)
* [动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) * [动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)
首先在回顾一下01背包的核心代码 首先在回顾一下01背包的核心代码
``` ```
@ -61,7 +61,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
} }
``` ```
至于为什么,我在[动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中也做了讲解。 至于为什么,我在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中也做了讲解。
dp状态图如下 dp状态图如下
@ -77,8 +77,8 @@ dp状态图如下
看过这两篇的话: 看过这两篇的话:
* [动态规划关于01背包问题你该了解这些](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w) * [动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)
* [动态规划关于01背包问题你该了解这些滚动数组](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA) * [动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)
就知道了01背包中二维dp数组的两个for遍历的先后循序是可以颠倒了一位dp数组的两个for循环先后循序一定是先遍历物品再遍历背包容量。 就知道了01背包中二维dp数组的两个for遍历的先后循序是可以颠倒了一位dp数组的两个for循环先后循序一定是先遍历物品再遍历背包容量。