Say you have an array for which the i-th 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).
Example 1:
Input: [2,4,1], k = 2 Output: 2 Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2 Output: 7 Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
思路:如果K >= n / 2,代表我能够买卖的次数已经超过了我能够买卖的极限,也就是当天买,第二天有利润就卖。那么我可以一直买卖,见利就收。题目变成了Best Time to Buy and Sell Stock II, 如果次数比较小,那么就要用dp;
这里我看了很多版本,觉得这个global和local的版本比较好理解;
global[i][j] 代表到第i天,最多交易j次,我全局能够得到的最大profit,全局的意思就是第i天,我可以啥也不做,也可以卖。
local[i][j] 代表的物理意义是:第i天,最多交易j次,而且第i天我必须卖的profit;
那么状态转移方程:全局的比较简单 global[i][j] = Math.max(global[i - 1][j], local[i][j]),这个没有问题。
局部的有点绕:local[i][j] = Math.max(part1, part2)
part1: (global[i - 1][j - 1] + Math.max(0, diff))也就是前一天全局最多和今天如果profit>0,我就卖,否则我不做任何事情。
part2: local[i - 1][j] + diff, 也就是我前一天卖了j次交易,但是最后一次交易我拖到第i天,次数不会增加,但是天数从[i - 1][j] 到了[i][j],注意的是无论diff >0 还是< 0,我都必须得卖的。这里是一个很tricky的地方,[i][j]的物理意义是第i天最多交易j次,但是j次的交易我可以拖时间,从i -1天拖到第i天,那么就是local[i - 1][j] 到local[i][j] 的状态转移方程;
class Solution {
public int maxProfit(int k, int[] prices) {
int n = prices.length;
if(k >= n / 2) {
return solveQuick(prices);
}
int[][] local = new int[n + 1][k + 1];
int[][] global = new int[n + 1][k + 1];
for(int i = 1; i < n; i++) {
int diff = prices[i] - prices[i - 1];
for(int j = 1; j <= k; j++) {
local[i][j] = Math.max(global[i - 1][j - 1] + Math.max(0, diff), local[i - 1][j] + diff);
global[i][j] = Math.max(global[i - 1][j], local[i][j]);
}
}
return global[n - 1][k];
}
private int solveQuick(int[] prices) {
int profit = 0;
for(int i = 1; i < prices.length; i++) {
if(prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
}