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).
Naive Way: As shown in best-time-to-buy-and-sell-stock-iii. There exists a DP solution within O(nk) run time and space.
The basic logic is
opt[i, j] // the maximum profit using i transactions in j days
// base case
opt[0, j] = 0 for all j
opt[i, 0] = 0 for all i
// iteration
opt[i, j] = max(opt[i, j-1], opt[i-1,t] + p[j] - p[t+1]) for 0<=t < j
However, this algorithm using gets TLE.
public class Solution {
public int maxProfit(int k, int[] prices) {
// edge case
if(k > prices.length/2) k= prices.length/2;
if(prices.length==0) return 0;
// DP
int opt[][] = new int[k+1][prices.length+1];
// base case
for(int i = 0;i <= k;i++) opt[i][0] = 0;
for(int j = 0;j <= prices.length;j++) opt[0][j] = 0;
// iteration
for(int i = 1;i <= k;i++){
int t = opt[i-1][0] - prices[0];
for(int j = 1;j <= prices.length;j++){
opt[i][j] = Math.max(opt[i][j-1], t + prices[j-1]);
if(j < prices.length) t = Math.max(t, opt[i-1][j] - prices[j]);
}
}
return opt[k][prices.length];
}
}
I don't know why this gets TLE, because this is already a high-efficiency algorithm. I saw the Discuss, some one put forward a great idea adding optimization for it. It is when k >= prices.length/2, that means we can make as many transactions as we can, that brings us the problem back to best-time-to-buy-and-sell-stock-ii which can be simply solve in O(n) using a greedy approach. That helps narrow down a lot of tests case to O(n) run time.
public class Solution {
public int maxProfit(int k, int[] prices) {
// edge case
if(k > prices.length/2){
int sum = 0;
for(int i = 1;i < prices.length;i++)
sum += Math.max(prices[i] - prices[i-1],0);
return sum;
}
if(prices.length==0) return 0;
// DP
int opt[][] = new int[k+1][prices.length+1];
// base case
for(int i = 0;i <= k;i++) opt[i][0] = 0;
for(int j = 0;j <= prices.length;j++) opt[0][j] = 0;
// iteration
for(int i = 1;i <= k;i++){
int t = opt[i-1][0] - prices[0];
for(int j = 1;j <= prices.length;j++){
opt[i][j] = Math.max(opt[i][j-1], t + prices[j-1]);
if(j < prices.length) t = Math.max(t, opt[i-1][j] - prices[j]);
}
}
return opt[k][prices.length];
}
}
Improved Way: Is there a solution better than O(kn)? There is a post using O(n+klogn) run time and O(n) space. It's idea is first find all useful valley-peak pairs and then merge them into k pairs.
https://oj.leetcode.com/discuss/26745/c-solution-with-o-n-klgn-time-using-max-heap-and-stack
No comments:
Post a Comment