diff --git a/README.md b/README.md
index 80a37391..aae26979 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@
* [BAT级别技术面试流程和注意事项都在这里了](https://mp.weixin.qq.com/s/815qCyFGVIxwut9I_7PNFw)
* [深圳原来有这么多互联网公司,你都知道么?](https://mp.weixin.qq.com/s/Yzrkim-5bY0Df66Ao-hoqA)
* [北京有这些互联网公司,你都知道么?](https://mp.weixin.qq.com/s/FQTzoZtqXQ2rlS1UthGrag)
+ * [上海有这些互联网公司,你都知道么?](https://mp.weixin.qq.com/s/msqbX6eR2-JBQOYFfec4sg)
* 算法性能分析
* [究竟什么是时间复杂度,怎么求时间复杂度,看这一篇就够了](https://mp.weixin.qq.com/s/lYL9TSxLqCeFXIdjt4dcIw)
@@ -123,8 +124,7 @@
* [二叉树:一入递归深似海,从此offer是路人](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
* [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)
* [二叉树:前中后序迭代方式的写法就不能统一一下么?](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
- * [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)
- * [二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg)
+ * [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog) * [二叉树:你真的会翻转二叉树么?](https://mp.weixin.qq.com/s/6gY1MiXrnm-khAAJiIb5Bg)
* [本周小结!(二叉树)](https://mp.weixin.qq.com/s/JWmTeC7aKbBfGx4TY6uwuQ)
* [二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)
* [二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)
@@ -175,6 +175,7 @@
* [本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA)
* [本周小结!(回溯算法系列三)续集](https://mp.weixin.qq.com/s/kSMGHc_YpsqL2j-jb_E_Ag)
* [视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg)
+ * [视频来了!!回溯算法:组合问题](https://mp.weixin.qq.com/s/a_r5JR93K_rBKSFplPGNAA)
* [回溯算法:重新安排行程](https://mp.weixin.qq.com/s/3kmbS4qDsa6bkyxR92XCTA)
* [回溯算法:N皇后问题](https://mp.weixin.qq.com/s/lU_QwCMj6g60nh8m98GAWg)
* [回溯算法:解数独](https://mp.weixin.qq.com/s/eWE9TapVwm77yW9Q81xSZQ)
@@ -315,6 +316,7 @@
|[0454.四数相加II](https://github.com/youngyangyang04/leetcode/blob/master/problems/0454.四数相加II.md) |哈希表 |中等| **哈希**|
|[0455.分发饼干](https://github.com/youngyangyang04/leetcode/blob/master/problems/0455.分发饼干.md) |贪心 |简单| **贪心**|
|[0459.重复的子字符串](https://github.com/youngyangyang04/leetcode/blob/master/problems/0459.重复的子字符串.md) |字符创 |简单| **KMP**|
+|[0474.一和零](https://github.com/youngyangyang04/leetcode/blob/master/problems/0474.一和零.md) |动态规划 |中等| **多重背包** 好题目|
|[0486.预测赢家](https://github.com/youngyangyang04/leetcode/blob/master/problems/0486.预测赢家.md) |动态规划 |中等| **递归** **记忆递归** **动态规划**|
|[0491.递增子序列](https://github.com/youngyangyang04/leetcode/blob/master/problems/0491.递增子序列.md) |深度优先搜索 |中等|**深度优先搜索/回溯算法** 这个去重有意思|
|[0496.下一个更大元素I](https://github.com/youngyangyang04/leetcode/blob/master/problems/0496.下一个更大元素I.md) |栈 |中等|**单调栈** 入门题目,但是两个数组还是有点绕的|
diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md
index 09486475..3e3f5881 100644
--- a/problems/0122.买卖股票的最佳时机II.md
+++ b/problems/0122.买卖股票的最佳时机II.md
@@ -1,23 +1,79 @@
-## 链接
-https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
+> 贪心有时候比动态规划更巧妙,更好用!
-## 思路
+# 122.买卖股票的最佳时机II
-首先要知道第0天买入,第3天卖出的利润:prices[3] - prices[0],相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + ()prices[1] - prices[0])
+题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
+
+给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
+
+设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
+
+注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
+
+
+示例 1:
+输入: [7,1,5,3,6,4]
+输出: 7
+解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
+
+示例 2:
+输入: [1,2,3,4,5]
+输出: 4
+解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
+
+示例 3:
+输入: [7,6,4,3,1]
+输出: 0
+解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
+
+提示:
+* 1 <= prices.length <= 3 * 10 ^ 4
+* 0 <= prices[i] <= 10 ^ 4
+
+# 思路
+
+本题首先要清楚两点:
+
+* 只有一只股票!
+* 当前只有买股票或者买股票的操作
+
+想获得利润至少要两天为一个交易单元。
+
+## 贪心算法
+
+这道题目可能我们只会想,选一个低的买入,在选个高的卖,在选一个低的买入.....循环反复。
+
+**如果想到其实最终利润是可以分解的,那么本题就很容易了!**
+
+如果分解呢?
+
+假如第0天买入,第3天卖出,那么利润为:prices[3] - prices[0]。
+
+相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。
+
+**此时就是把利润分解为每天为单位的维度,而不是从0天到第3天整体去考虑!**
那么根据prices可以得到每天的利润序列:(prices[i] - prices[i - 1]).....(prices[1] - prices[0])。
-可以发现,我们需要收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润就可以了,不需要记录区间。
-
-**这就是贪心所贪的地方,只收集正利润**。
-
如图:
-
+
+
+一些同学陷入:第一天怎么就没有利润呢,第一天到底算不算的困惑中。
+
+第一天当然没有利润,至少要第二天才会有利润,所以利润的序列比股票序列少一天!
+
+从图中可以发现,其实我们需要收集每天的正利润就可以,**收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润,不需要记录区间**。
+
+那么只收集正利润就是贪心所贪的地方!
+
+**局部最优:收集每天的正利润,全局最优:求得最大利润**。
+
+局部最优可以推出全局最优,找不出反例,试一试贪心!
对应C++代码如下:
-```
+```C++
class Solution {
public:
int maxProfit(vector& prices) {
@@ -29,6 +85,47 @@ public:
}
};
```
+* 时间复杂度O(n)
+* 空间复杂度O(1)
+
+## 动态规划
+
+动态规划将在下一个系列详细讲解,本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
+
+```C++
+class Solution {
+public:
+ int maxProfit(vector& prices) {
+ // dp[i][1]第i天持有的最多现金
+ // dp[i][0]第i天持有股票后的最多现金
+ int n = prices.size();
+ vector> dp(n, vector(2, 0));
+ dp[0][0] -= prices[0]; // 持股票
+ for (int i = 1; i < n; i++) {
+ // 第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金, 第i-1天持现金-买第i天的股票)
+ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
+ // 第i天持有最多现金 = max(第i-1天持有的最多现金,第i-1天持有股票的最多现金+第i天卖出股票)
+ dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
+ }
+ return max(dp[n - 1][0], dp[n - 1][1]);
+ }
+};
+```
+* 时间复杂度O(n)
+* 空间复杂度O(n)
+
+# 总结
+
+股票问题其实是一个系列的,属于动态规划的范畴,因为目前在讲解贪心系列,所以股票问题会在之后的动态规划系列中详细讲解。
+
+**可以看出有时候,贪心往往比动态规划更巧妙,更好用,所以别小看了贪心算法**。
+
+**本题中理解利润拆分是关键点!** 不要整块的去看,而是把整体利润拆为每天的利润。
+
+一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。
+
+就酱,「代码随想录」是技术公众号里的一抹清流,值得推荐给你的朋友同学们!
+
> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),期待你的关注!
diff --git a/problems/0300.最长上升子序列.md b/problems/0300.最长上升子序列.md
index b0a3668e..5582c8ac 100644
--- a/problems/0300.最长上升子序列.md
+++ b/problems/0300.最长上升子序列.md
@@ -1,4 +1,5 @@
+## 思路
* dp[i]的定义
dp[i]表示i之前包括i的最长上升子序列。
@@ -11,6 +12,7 @@ dp[i]表示i之前包括i的最长上升子序列。
* 状态转移方程
+位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 + 1 的最大值。
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md
new file mode 100644
index 00000000..ba154584
--- /dev/null
+++ b/problems/0474.一和零.md
@@ -0,0 +1,32 @@
+
+搞不懂 leetcode后台是什么牛逼的编译器,初始化int dp[101][101] = {0}; 可以 ,int dp[101][101];就不行,有其他默认值,坑死。
+代码我做了实验,后台会拿findMaxForm,运行两次,取第二次的结果,dp有上次记录的数值。
+
+```
+// 即使做了很多动态规划的题目,做这个依然懵逼
+// 这道题目有点 程序员自己给自己出难进急转弯的意思
+// 该子集中 最多 有 m 个 0 和 n 个 1 。 指的是整体子集
+// 这是二维背包,多重背包
+// dp[i][j] 有i个0,j个1最大有多少个子集,但是遍历的时候 顶部是哪里呢?
+class Solution {
+public:
+ int findMaxForm(vector& strs, int m, int n) {
+ int dp[101][101] = {0}; // 默认初始化0
+ for (int i = 0; i < strs.size(); i++) {
+ int oneNum = 0, zeroNum = 0;
+ for (char c : strs[i]) {
+ if (c == '0') zeroNum++;
+ else oneNum++;
+ }
+ // 果然还是从后向前,模拟01背包
+ for (int j = m; j >= zeroNum; j--) {
+ for (int k = n; k >= oneNum; k--) {
+ dp[j][k] = max(dp[j][k], dp[j - zeroNum][k - oneNum] + 1);
+ }
+ }
+ }
+ return dp[m][n];
+ }
+};
+
+```