1
- ## 链接
2
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
1
+ > 贪心有时候比动态规划更巧妙,更好用!
3
2
4
- ## 思路
3
+ # 122.买卖股票的最佳时机II
5
4
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/
7
6
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
+ * 当前只有买股票或者买股票的操作
9
39
10
- 可以发现,我们需要收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润就可以了,不需要记录区间 。
40
+ 想获得利润至少要两天为一个交易单元 。
11
41
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] )。
13
57
14
58
如图:
15
59
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
+ 局部最优可以推出全局最优,找不出反例,试一试贪心!
17
73
18
74
对应C++代码如下:
19
75
20
- ```
76
+ ``` C++
21
77
class Solution {
22
78
public:
23
79
int maxProfit(vector<int >& prices) {
@@ -29,6 +85,47 @@ public:
29
85
}
30
86
};
31
87
```
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
+
32
129
33
130
> 我是[程序员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),期待你的关注!
34
131
0 commit comments