题目描述:
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:输入: [7,1,5,3,6,4]
输出: 7
示例 2:输入: [1,2,3,4,5]
输出: 4
示例 3: 输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int profit = 0;
bool already_buy = false;
int buy_price = 0;
int i = 0;
for(; i < prices.size()-1; i++){
if(prices[i] < prices[i+1] && !already_buy) {
buy_price = prices[i];
already_buy = true;
continue;
}
if(prices[i] > prices[i+1] && !already_buy) continue;
if(prices[i] < prices[i+1] && already_buy) continue;
if(prices[i] > prices[i+1] && already_buy) {
int tmpprofit = prices[i] - buy_price;
profit =profit+tmpprofit;
already_buy = false;
continue;
}
}
if(already_buy){
int tmp = prices[i] -buy_price;
profit = profit+tmp;
}
return profit;
}
};
我写的时候想法很简单, 遍历一下,遇低则买,遇高则等,再遇低才考虑在上一次卖出, 因此需要每次访问两个变量; 本来觉得效果已经很好了,官网给出的讲解算是又上升了一个层面;
官网的讲解:
由于股票的购买没有限制,因此整个问题等价于寻找 x 个不相交的区间 (l_i,r_i](li ,ri ] 使得如下的总价格最大化; 在li时买入,在ri时卖出; 这里的x就代表了交易次数(一次买入和卖出表示一次交易)
但是对于每一个这样的区间,其最后的收益总和, 等价于每一个跨度为1 的小区间的差值总和; 例如:
[6 1 3 2 4 7] 对于这组数据,我们能找到两次交易机会,[1, 3] 和[2,7]
而第二次交易机会的总收益 7-2 = 5, 与 [2 , 4] + [4, 7] 这两个区间的差值和;
基于这个想法, 官方给出的贪心算法相当简单; 将寻找大区间的问题转换成了寻找每一个小的增区间;
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
int n = prices.size();
for (int i = 1; i < n; ++i) {
ans += max(0, prices[i] - prices[i - 1]);
}
return ans;
}
};
看到一个关于贪心算法思路的讲解, 很适合今天的这道题:
- 建立数学模型来描述问题
- 把求解的问题分成若干个子问题
- 对每个子问题求解,得到子问题的局部最优解
- 把子问题的解局部最优解合成原来问题的一个解
如何判断一个题是否适合使用贪心算法:
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解;
REF: