Thursday, August 20, 2015

Best Time to Buy and Sell Stock IV | Leetcode

Say you have an array for which the ith 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).

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

---

Solution: There are two parts needed to solve this problem. The first part is the simple case, when k >= length / 2, you can have as many transactions as you want. In this case, just buy and sell everyday when there is a profit to be made.

The second part is the dynamic programming part. Go through the prices array and simulate sell or hold on each price point. Then you will get the maximum profit in the last element of the sell array.

Algorithm 1 is the more easily understandable solution, but does not pass big test cases.
Algorithm 2 is the solution that will pass the leetcode submission.

Algorithm 1: Does not pass big test cases
public class Solution {
    private Integer[][] maxProfitCache;
    private int[] prices;
    
    public int maxProfit(int k, int[] prices) {
        maxProfitCache = new Integer[prices.length][prices.length];
        this.prices = prices;
        return maxProfit(k, 0, prices.length - 1);
    }
    
    private int maxProfit(int k, int first, int last) {
        if (first >= last) return 0;
        int max = maxProfit(first, last);
        if (k == 1) return max;
        
        for (int i = first + 1; i < last; i++) {
            max = Math.max(max, maxProfit(k - 1, first, i) + maxProfit(i, last));
        }
        return max;
    }
    
    private int maxProfit(int first, int last) {
        Integer cached = maxProfitCache[first][last];
        if (cached != null) return cached;

        int max = 0;
        int lowest = prices[first];
        for (int i = first + 1; i <= last; i++) {
            lowest = Math.min(lowest, prices[i]);
            max = Math.max(max, prices[i] - lowest);
        }
        
        maxProfitCache[first][last] = max;
        return max;
    }
}
Algorithm 2: Dynamic Programming
public class Solution {
    public int maxProfit(int k, int[] prices) {
        int length = prices.length;
        if (length < 2) return 0;
        
        // Simple case.
        if (k >= length / 2) {
            int profit = 0;
            for (int i = 1; i < length; i++) {
                profit += Math.max(prices[i] - prices[i - 1], 0);
            }
            return profit;
        }
        
        // Dynamic programming.
        int[] hold = new int[k + 1];
        int[] sell = new int[k + 1];
        
        Arrays.fill(hold, Integer.MIN_VALUE);

        for (int price: prices) {
            for (int i = 1; i <= k; i++) {
                sell[i] = Math.max(sell[i], hold[i] + price);
                hold[i] = Math.max(hold[i], sell[i - 1] - price);
            }
        }
        
        return sell[k];
    }
}

No comments: