原題地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/
題目描述
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.
設計一個算法來計算最大收益。你至多可以完成k次交易。
Note:
注意:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
你不能同時進行多次交易(即,在你買入股票之前必須賣掉手裏的股票)。
解題思路
這是這個系列的第四題,前三題如下:
參考了網上諸多大神的代碼,有位大神說這個題是II和III的結合版。在某特殊情況下是II,其他情況下是III的升級。後面再詳述。
網上的代碼大致分兩種,時間複雜度O(n*k),空間複雜度O(n),但是兩種的角度不同。
第一種,大家可以看下面的博文:
另外一種,大家可以參考以下文章:
第一種維護兩個數組,local[][]和global[][],其中global[i][j]表示到第i天時完成j次交易的最大收益,local[i][j]表示到第i天時完成j次交易並且最後一次交易發生在第i天時的最大收益。
global的推導公式如下:
global[i][j] = max(local[i][j], global[i-1][j]);
即,到第i天完成j次交易的最大收益,要麼是第j次交易發生在第i天時的最大收益,要麼是到第i-1天完成j次交易時的最大收益。
local的推導公式如下:
local[i][j] = max(global[i-1][j-1]+max(diff,0), local[i-1][j]+diff);
需要看兩個量,第一個是全局global到i-1天進行j-1次交易,然後加上今天的交易,如果今天是賺錢的話(也就是前面只要j-1次交易,最後一次交易取當前天);第二個量則是取local第i-1天j次交易,然後加上今天的差值(這裏因爲local[i-1][j]比如包含第i-1天賣出的交易,所以現在變成第i天賣出,並不會增加交易次數,而且這裏無論diff是不是大於0都一定要加上,因爲否則就不滿足local[i][j]必須在最後一天賣出的條件了)。
代碼請看代碼一。
第二種想法是維護兩個數組buy和sell,buy[i]表示完成第i筆交易的買入動作時的最大收益,sell[i]表示完成第i筆交易的賣出動作時的最大收益。初始情況下buy[i]=MIN,sell[i]=0。
buy[i]的推導
buy[i] = max(buy[i], sell[i-1]-prices[j])
即,第i-1次完成賣出時的最大收益再減去第j天的價格,有可能更新第i次完成買入時的最大收益。
sell[i]的推導
sell[i] = max(sell[i], buy[i]+prices[j])
即,第i次完成買入時的最大收益再加上第j天的價格,有可能更新第i次賣出時的最大收益。
代碼請見代碼二。
代碼
代碼一
class Solution {
public:
/**
* 計算最大收益
* @param k : 至多進行k次買賣
* @param prices : 每日價格
* @return : 最大收益
*/
int maxProfit(int k, vector<int>& prices) {
int pricesSize = prices.size();
/* 如果價格數據爲空或只有一個數據,或者不能進行買賣,返回0 */
if (pricesSize <= 1 || k <= 0) return 0;
/* k>=pricesSize,相當於不限交易次數 */
if (k >= pricesSize) {
int max = 0;
for (int i = 1; i < pricesSize; ++i)
if (prices[i] > prices[i-1])
max += prices[i] - prices[i-1];
return max;
}
int *local = new int[k + 1];
int *global = new int[k + 1];
for (int i = 0; i <= k; ++i)
local[i] = global[i] = 0;
for (int i = 1; i < pricesSize; ++i) {
int diff = prices[i] - prices[i - 1];
for (int j = k; j > 0; --j) {
local[j] = bigger(global[j - 1] + bigger(diff, 0), local[j] + diff);
global[j] = bigger(local[j], global[j]);
}
}
int max = global[k];
delete(local);
delete(global);
return max;
}
private:
int bigger(int a, int b) {
return a > b ? a : b;
}
};
完整代碼 https://github.com/Orange1991/leetcode/blob/master/188/cpp/solution2.cpp
代碼二
class Solution {
public:
/**
* 計算最大收益
* @param k : 至多進行k次買賣
* @param prices : 每日價格
* @return : 最大收益
*/
int maxProfit(int k, vector<int>& prices) {
int pricesSize = prices.size();
/* 如果價格數據爲空或只有一個數據,或者不能進行買賣,返回0 */
if (pricesSize <= 1 || k <= 0) return 0;
/* k>=pricesSize,相當於不限交易次數 */
if (k >= pricesSize) {
int max = 0;
for (int i = 1; i < pricesSize; ++i)
if (prices[i] > prices[i-1])
max += prices[i] - prices[i-1];
return max;
}
// 第i次買入和賣出時的最大收益
vector<int> buy(pricesSize + 1, numeric_limits<int>::min()), sell(pricesSize + 1);
for (int day = 0; day < pricesSize; ++day) {
for (int transaction = 1; transaction <= k; ++transaction) {
buy[transaction] = bigger(buy[transaction], sell[transaction - 1] - prices[day]);
sell[transaction] = bigger(sell[transaction], buy[transaction] + prices[day]);
}
}
return sell[k];
}
private:
int bigger(int a, int b) {
return a > b ? a : b;
}
};
完整代碼 https://github.com/Orange1991/leetcode/blob/master/188/cpp/main.cpp
2015/8/12