题目:
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
思路:
这道题目自己没有独立做出来,我在网上参考了两种最好的解法,这里和大家分享。
1、记录局部最优解和全局最优解的动态规划法:用local[i][j]表示到达第i天时,最多进行j次交易的局部最优解;用global[i][j]表示到达第i天时,最多进行j次交易的全局最优解。它们两者的关系如下(其中diff = prices[i] - prices[i - 1]):
local[i][j] = max(global[i-1][j-1] + max(diff, 0), local[i-1][j] + diff);
global[i][j] = max(global[i-1][j], local[i][j]);
其中的local[i-1][j] + diff就是为了避免第i天交易和第i-1天交易合并成为一次交易而少一次交易收益。算法的时间复杂度是O(n^2),空间复杂度也是O(n^2)。不过由于local和global的递推公式只和它临近的元素有关,所以目测空间复杂度还可以进一步降低到O(n)。这里偷个懒,不弄了。
2、记录买入卖出的动态规划法:可以记录k次交易每次买入之后和卖出之后最大的利润。第i次买操作买下当前股票之后剩下的最大利润为第(i-1)次卖掉股票之后的利润 - 当前的股票价格,状态转移方程为:buys[i] = max(sells[i - 1] - current_price, buys[i]). 第i次卖操作卖掉当前股票之后剩下的最大利润为第i次买操作之后剩下的利润 + 当前的股票价格。状态转移方程为:sells[i] = max(buys[i] + current_price, sells[i])。最终所求即为sells[k]。
代码:
1、记录局部最优解和全局最优解的动态规划法:
class Solution {
public:
int maxProfit(int k, vector& prices) {
if(prices.size() < 2) {
return 0;
}
int days = prices.size();
if(k >= days / 2) {
return maxProfit(prices);
}
vector> local(days, vector(k + 1, 0));
vector> global(days, vector(k + 1, 0));
for(int i = 1; i < days; ++i) {
int diff = prices[i] - prices[i - 1];
for(int j = 1; j <= k; ++j) {
local[i][j] = max(global[i-1][j-1], local[i-1][j] + diff);
global[i][j] = max(global[i-1][j], local[i][j]);
}
}
return global[days - 1][k];
}
private:
int maxProfit(vector& prices) {
int max_profit = 0;
for(int i = 1; i < prices.size(); ++i) {
if(prices[i] > prices[i-1]) {
max_profit += prices[i] - prices[i-1];
}
}
return max_profit;
}
};
2、记录买入卖出的动态规划法:
class Solution {
public:
int maxProfit(int k, vector& prices) {
if(prices.size() < 2) {
return 0;
}
int days = prices.size(), ret = 0;
if(k >= days / 2) {
return maxProfit(prices);
}
vector buys(days + 1, INT_MIN);
vector sells(days + 1, 0);
for (int i = 0; i < days; ++i) {
for (int j = 1; j <= k; ++j) {
buys[j] = max(sells[j - 1] - prices[i], buys[j]);
sells[j] = max(buys[j] + prices[i], sells[j]);
}
}
return sells[k];
}
private:
int maxProfit(vector& prices) {
int max_profit = 0;
for(int i = 1; i < prices.size(); ++i) {
if(prices[i] > prices[i-1]) {
max_profit += prices[i] - prices[i-1];
}
}
return max_profit;
}
};