思路:动态规划
dp[ i ][ j ][ k ]
i - 到第 i 天
j - 最多交易 j 次
k - 0:当前持股 / 1:当前不持股
状态转移方程
1 2 3 4 5 6 7 8 9 10
| // 第i天,最多交易j次,当前不持股 dp[i][j][0] = MAX{ dp[i-1][j][0], // 本次不持-上次就不持 dp[i-1][j-1][1] + 差价 // 本次不持-本次卖 } // 第i天,最多交易j次,当前持股 dp[i][j][1] = MAX{ dp[i-1][j][0], // 本次持-本次买 dp[i-1][j][1] + 差价 // 本次持-上次就持 }
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public int getdp(int i,int j,int k,int[][][] dp,int[] prices){ if(dp[i][j][k]==-1){ if(i<1){ dp[i][j][0]=0; dp[i][j][1]=0; }else{ int dp1 = getdp(i-1,j,0,dp,prices); int dp2 = j>0 ? getdp(i-1,j-1,1,dp,prices)+prices[i]-prices[i-1] : 0; dp[i][j][0] = Math.max(dp1,dp2); int dp3 = getdp(i-1,j,0,dp,prices); int dp4 = getdp(i-1,j,1,dp,prices)+prices[i]-prices[i-1]; dp[i][j][1] = Math.max(dp3,dp4); } } return dp[i][j][k]; }
|
坑:当k很大时,内存会爆,此时相当于不限制交易次数,直接用贪心解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Solution { public int maxProfit(int k, int[] prices) { if(prices.length<2){ return 0; }
if(k > prices.length/2){ int value = 0; for(int i=1;i<prices.length;i++){ value += prices[i]>prices[i-1] ? prices[i]-prices[i-1] : 0; } return value; }
int[][][] dp = new int[prices.length][k+1][2]; for(int i=0;i<prices.length;i++){ for(int j=0;j<k+1;j++){ Arrays.fill(dp[i][j],-1); } }
return getdp(prices.length-1,k,0,dp,prices); }
public int getdp(int i,int j,int k,int[][][] dp,int[] prices){...} }
|
用这一套解法干掉4题
Leetcode 121 买卖股票的最佳时机 —— 最多交易1次
令 k = 1
Leetcode 122 买卖股票的最佳时机 II —— 不限次数
直接贪心
Leetcode 123 买卖股票的最佳时机 III —— 最多交易2次
令 k = 2
Leetcode 188 买卖股票的最佳时机 IV —— 最多交易k次