1- ## 链接
2- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
1+ > 贪心有时候比动态规划更巧妙,更好用!
32
4- ## 思路
3+ # 122.买卖股票的最佳时机II
54
6- 首先要知道第0天买入,第3天卖出的利润:prices [ 3 ] - prices [ 0 ] ,相当于(prices [ 3 ] - prices [ 2 ] ) + (prices [ 2 ] - prices [ 1 ] ) + ()prices [ 1 ] - prices [ 0 ] )
5+ 题目链接: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
76
8- 那么根据prices可以得到每天的利润序列:(prices[ i] - prices[ i - 1] ).....(prices[ 1] - prices[ 0] )。
7+ 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
8+
9+ 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
10+
11+ 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
12+
13+
14+ 示例 1:
15+ 输入: [ 7,1,5,3,6,4]
16+ 输出: 7
17+ 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
18+
19+ 示例 2:
20+ 输入: [ 1,2,3,4,5]
21+ 输出: 4
22+ 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
23+
24+ 示例 3:
25+ 输入: [ 7,6,4,3,1]
26+ 输出: 0
27+ 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
28+
29+ 提示:
30+ * 1 <= prices.length <= 3 * 10 ^ 4
31+ * 0 <= prices[ i] <= 10 ^ 4
32+
33+ # 思路
34+
35+ 本题首先要清楚两点:
36+
37+ * 只有一只股票!
38+ * 当前只有买股票或者买股票的操作
939
10- 可以发现,我们需要收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润就可以了,不需要记录区间 。
40+ 想获得利润至少要两天为一个交易单元 。
1141
12- ** 这就是贪心所贪的地方,只收集正利润** 。
42+ ## 贪心算法
43+
44+ 这道题目可能我们只会想,选一个低的买入,在选个高的卖,在选一个低的买入.....循环反复。
45+
46+ ** 如果想到其实最终利润是可以分解的,那么本题就很容易了!**
47+
48+ 如果分解呢?
49+
50+ 假如第0天买入,第3天卖出,那么利润为:prices[ 3] - prices[ 0] 。
51+
52+ 相当于(prices[ 3] - prices[ 2] ) + (prices[ 2] - prices[ 1] ) + (prices[ 1] - prices[ 0] )。
53+
54+ ** 此时就是把利润分解为每天为单位的维度,而不是从0天到第3天整体去考虑!**
55+
56+ 那么根据prices可以得到每天的利润序列:(prices[ i] - prices[ i - 1] ).....(prices[ 1] - prices[ 0] )。
1357
1458如图:
1559
16- <img src =' ../pics/122.买卖股票的最佳时机II.png ' width =600 > </img ></div >
60+ ![ 122.买卖股票的最佳时机II] ( https://img-blog.csdnimg.cn/2020112917480858.png )
61+
62+ 一些同学陷入:第一天怎么就没有利润呢,第一天到底算不算的困惑中。
63+
64+ 第一天当然没有利润,至少要第二天才会有利润,所以利润的序列比股票序列少一天!
65+
66+ 从图中可以发现,其实我们需要收集每天的正利润就可以,** 收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润,不需要记录区间** 。
67+
68+ 那么只收集正利润就是贪心所贪的地方!
69+
70+ ** 局部最优:收集每天的正利润,全局最优:求得最大利润** 。
71+
72+ 局部最优可以推出全局最优,找不出反例,试一试贪心!
1773
1874对应C++代码如下:
1975
20- ```
76+ ``` C++
2177class Solution {
2278public:
2379 int maxProfit(vector<int >& prices) {
@@ -29,6 +85,47 @@ public:
2985 }
3086};
3187```
88+ * 时间复杂度O(n)
89+ * 空间复杂度O(1)
90+
91+ ## 动态规划
92+
93+ 动态规划将在下一个系列详细讲解,本题解先给出我的C++代码(带详细注释),感兴趣的同学可以自己先学习一下。
94+
95+ ```C++
96+ class Solution {
97+ public:
98+ int maxProfit(vector<int>& prices) {
99+ // dp[i][1]第i天持有的最多现金
100+ // dp[i][0]第i天持有股票后的最多现金
101+ int n = prices.size();
102+ vector<vector<int>> dp(n, vector<int>(2, 0));
103+ dp[0][0] -= prices[0]; // 持股票
104+ for (int i = 1; i < n; i++) {
105+ // 第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金, 第i-1天持现金-买第i天的股票)
106+ dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
107+ // 第i天持有最多现金 = max(第i-1天持有的最多现金,第i-1天持有股票的最多现金+第i天卖出股票)
108+ dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
109+ }
110+ return max(dp[n - 1][0], dp[n - 1][1]);
111+ }
112+ };
113+ ```
114+ * 时间复杂度O(n)
115+ * 空间复杂度O(n)
116+
117+ # 总结
118+
119+ 股票问题其实是一个系列的,属于动态规划的范畴,因为目前在讲解贪心系列,所以股票问题会在之后的动态规划系列中详细讲解。
120+
121+ ** 可以看出有时候,贪心往往比动态规划更巧妙,更好用,所以别小看了贪心算法** 。
122+
123+ ** 本题中理解利润拆分是关键点!** 不要整块的去看,而是把整体利润拆为每天的利润。
124+
125+ 一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。
126+
127+ 就酱,「代码随想录」是技术公众号里的一抹清流,值得推荐给你的朋友同学们!
128+
32129
33130> 我是[程序员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),期待你的关注!
34131
0 commit comments