Intuition
Generalize the two-transaction trick to k: keep a buy and a sell value for each of the k transactions. For every price, update transaction j's buy from transaction j-1's sell, and its sell from its own buy. If k is large enough to allow a trade on every rise, fall back to the unlimited-transaction greedy sum.
Explanation
Idea
With at most k transactions, keep two arrays: buy[j] = best balance after the jth buy, sell[j] = best after the jth sell. For each price, transaction j buys off the profit of transaction j-1's sell:
buy[j] = max(buy[j], sell[j-1] - price)
sell[j] = max(sell[j], buy[j] + price)
Shortcut: if k >= n/2, there aren't enough days to constrain us — any number of trades is allowed — so just sum every positive day-to-day rise (the Stock II answer).
Algorithm
- If
k >= n/2, return the sum of all positive consecutive differences. - Otherwise
buy[1..k] = -∞,sell[0..k] = 0. For each price, updatebuy[j],sell[j]forjfrom 1 to k. Returnsell[k].
Worked example: k = 2, prices = [3,2,6,5,0,3]
Buy at 2 sell at 6 (+4); buy at 0 sell at 3 (+3). Total 7.
Complexity
- Time: O(n·k) (or O(n) via the shortcut).
- Space: O(k).
Implementation
import java.util.Arrays;
class Solution {
public int maxProfit(int k, int[] prices) {
int n = prices.length;
if (n == 0) {
return 0;
}
if (k >= n / 2) {
int profit = 0;
for (int i = 1; i < n; i++) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
int[] buy = new int[k + 1];
int[] sell = new int[k + 1];
Arrays.fill(buy, Integer.MIN_VALUE);
for (int p : prices) {
for (int j = 1; j <= k; j++) {
buy[j] = Math.max(buy[j], sell[j - 1] - p);
sell[j] = Math.max(sell[j], buy[j] + p);
}
}
return sell[k];
}
}