题目来源:力扣第188题
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。示例 2:
输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 ;随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
AC代码:
class Solution {
public:
int maxProfit(int k, vector& prices) {
if(prices.size()==0) return 0;
if(k>prices.size()/2){
int profit=0;
bool ifbuy=0;
for(int i=0;iprices[i+1]&&ifbuy==1){
profit+=prices[i];
ifbuy=0;
}
}
return profit;
}
int money[prices.size()][k+1][2];
for(int i=0;i
思路:
第4行用于处理天数为0的情况;
第5行至第24行针对性地处理不需要考虑k的特殊情况(完成一笔交易至少需要买入、卖出两天,若允许的最大交易次数k>总天数/2,则相当于处理这组数据时无需考虑k),提高程序对某些数据的处理速度。
第25行至第44行,用于处理一般情况:
用money[i][j][0]表示在第i+1天,剩余可交易j次,且当天收盘后未持有股票的情况下,拥有资金的最大值;
用money[i][j][1]表示在第i+1天,剩余可交易j次,且当天收盘后持有股票的情况下,拥有资金的最大值;
设初始时拥有资金为0,资金可以为负数。约定每次买入时,当天剩余可交易次数减一。
类似数学中的数学归纳法,首先讨论初始状态:
对于任意剩余交易次数j,money[0][j][0]的值均为0,即第一天未买入股票,无论还能交易几次,当天最多拥有0元;
对于任意剩余交易次数j,money[0][j][1]的值均为当天的股票价格的相反数,即第一天买入股票,无论还能交易几次,当天最多拥有-prices[i]元;
另外还需将money[i][k][0]的值初始化为0(i为允许的任意值); 即无论处在第几天,若仍允许的交易次数为最大值k,说明到目前为止未进行任何股票交易,拥有资金仍为0;
money[i][k][1]则无任何意义,因为不可能出现买入了但剩余可交易次数仍为最大次数的情况。
之后从初始状态出发不断推导其他状态,通过对money数组的遍历(不考虑j==k的情况,因为在初始状态中已经讨论),便可以得到在任意一天,剩余可交易次数为任意次,此时持有/未持有股票情况下,拥有资金的最大值:
money[i][j][0]=max(money[i-1][j][0],money[i-1][j][1]+prices[i]);
money[i][j][1]=max(money[i-1][j][1],money[i-1][j+1][0]-prices[i]);
最终,数据money[prices.size()-1][0][0]即为在最后一天持有资金的最大值,即为能获得的最大利润。
例如:对于输入[2,4,1],k=2,若使用该一般算法,则首先计算初始值:
money[0][0][0]=0
money[0][0][1]=-2
money[0][1][0]=0
money[0][1][1]=-2
money[0][2][0]=0
接着,讨论第二天的情况,第二天的每一个状态必定由第一天的某个状态变化而来,如money[1][0][0]的上一个状态必定为 money[0][0][0]=0(第1天与第2天均未持有股票)或money[0][0][1](第1天持有股票,在第2天卖出),money[1][0][1]上一个状态必定为money[0][0][1](第1天就已经持有股票,第2天未卖出)或money[0][1][0]=0(第1天未持有股票,第2天消耗一次买入机会买入)。因此,可以通过第一天的状态推导出第二天各个状态的最大取值。
同理,第n天各个状态的最大取值可由第n-1天各个状态的最大取值推到得到。