package com.interview.dynamic; import java.util.Deque; import java.util.LinkedList; /** * Date 12/22/2015 * @author Tushar Roy * * Given stockc prices for certain days and at most k transactions how to buy and sell * to maximize profit. * * Time complexity - O(number of transactions * number of days) * Space complexity - O(number of transcations * number of days) * * https://leetcode.com/discuss/15153/a-clean-dp-solution-which-generalizes-to-k-transactions */ public class StockBuySellKTransactions { /** * Below solution is accepted by leetcode and runs in space proportional to prices length. */ public int maxProfitLinearSpace(int k, int[] prices) { if (k == 0 || prices.length == 0) { return 0; } if (k >= prices.length) { return allTimeProfit(prices); } int[] T = new int[prices.length]; int[] prev = new int[prices.length]; for (int i = 1; i <= k; i++) { int maxDiff = -prices[0]; for (int j = 1; j < prices.length; j++) { T[j] = Math.max(T[j - 1], maxDiff + prices[j]); maxDiff = Math.max(maxDiff, prev[j] - prices[j]); } for (int j = 1; j < prices.length; j++) { prev[j] = T[j]; } } return T[T.length - 1]; } public int allTimeProfit(int arr[]){ int profit = 0; int localMin = arr[0]; for(int i=1; i < arr.length;i++){ if(arr[i-1] >= arr[i]){ localMin = arr[i]; }else{ profit += arr[i] - localMin; localMin = arr[i]; } } return profit; } /** * This is faster method which does optimization on slower method * Time complexity here is O(K * number of days) * * Formula is * T[i][j] = max(T[i][j-1], prices[j] + maxDiff) * maxDiff = max(maxDiff, T[i-1][j] - prices[j]) */ public int maxProfit(int prices[], int K) { if (K == 0 || prices.length == 0) { return 0; } int T[][] = new int[K+1][prices.length]; for (int i = 1; i < T.length; i++) { int maxDiff = -prices[0]; for (int j = 1; j < T[0].length; j++) { T[i][j] = Math.max(T[i][j-1], prices[j] + maxDiff); maxDiff = Math.max(maxDiff, T[i-1][j] - prices[j]); } } printActualSolution(T, prices); return T[K][prices.length-1]; } /** * This is slow method but easier to understand. * Time complexity is O(k * number of days ^ 2) * T[i][j] = max(T[i][j-1], max(prices[j] - prices[m] + T[i-1][m])) where m is 0...j-1 */ public int maxProfitSlowSolution(int prices[], int K) { if (K == 0 || prices.length == 0) { return 0; } int T[][] = new int[K+1][prices.length]; for (int i = 1; i < T.length; i++) { for (int j = 1; j < T[0].length; j++) { int maxVal = 0; for (int m = 0; m < j; m++) { maxVal = Math.max(maxVal, prices[j] - prices[m] + T[i-1][m]); } T[i][j] = Math.max(T[i][j-1], maxVal); } } printActualSolution(T, prices); return T[K][prices.length - 1]; } public void printActualSolution(int T[][], int prices[]) { int i = T.length - 1; int j = T[0].length - 1; Deque<Integer> stack = new LinkedList<>(); while(true) { if(i == 0 || j == 0) { break; } if (T[i][j] == T[i][j-1]) { j = j - 1; } else { stack.addFirst(j); int maxDiff = T[i][j] - prices[j]; for (int k = j-1; k >= 0; k--) { if (T[i-1][k] - prices[k] == maxDiff) { i = i - 1; j = k; stack.addFirst(j); break; } } } } while(!stack.isEmpty()) { System.out.println("Buy at price " + prices[stack.pollFirst()]); System.out.println("Sell at price " + prices[stack.pollFirst()]); } } public static void main(String args[]) { StockBuySellKTransactions sbt = new StockBuySellKTransactions(); int prices[] = {2, 5, 7, 1, 4, 3, 1, 3}; System.out.println("Max profit fast solution " + sbt.maxProfit(prices, 3)); System.out.println("Max profit slow solution " + sbt.maxProfitSlowSolution(prices, 3)); } }