package com.freetymekiyan.algorithms.level.hard; import java.util.Arrays; /** * Say you have an array for which the ith element is the price of a given * stock on day i. * <p> * Design an algorithm to find the maximum profit. You may complete at most k * transactions. * <p> * Note: * You may not engage in multiple transactions at the same time (ie, you must * sell the stock before you buy again). * <p> * Tags: DP */ class BestTimeStock4 { public static void main(String[] args) { // 2, [3,2,6,5,0,3] // 2, [3,3,5,0,0,3,1,4] BestTimeStock4 b = new BestTimeStock4(); int[] A = new int[]{3, 3, 5, 0, 0, 3, 1, 4}; int[] B = new int[]{3, 2, 6, 5, 0, 3}; System.out.println(b.maxProfitOpt(2, A)); System.out.println(b.maxProfit(2, A)); System.out.println(b.maxProfitOpt(2, B)); System.out.println(b.maxProfit(2, B)); } /** * DP, bottom-up, O(kn) Time, O(n) Space * If k >= n/2, we can have transactions any time, O(n). * dp[k][i+1] represents the max profit of using [0, i] and k transactions * It can be dp[k-1][i+1](add 1 more transaction changes nothing) * It can be dp[k][i](prices[i] changes nothing) * It can be prices[i] + max(dp[k-1][j] - prices[j]), 0 <= j < i * means prices[i] will change the max profit, find the biggest from k-1 * transacions and add prices[i] * dp[k][i+1] = max(dp[k-1][i+1], dp[k][i], prices[i] + max(dp[k-1][j] - * prices[j])), (0 <= j < i) */ public int maxProfitOpt(int k, int[] prices) { if (prices == null || prices.length < 2 || k == 0) { return 0; } int n = prices.length; int res = 0; if (k >= n / 2) { // as many transactions as possible for (int i = 1; i < n; i++) { if (prices[i] > prices[i - 1]) { res += prices[i] - prices[i - 1]; } } return res; } int[] cur = new int[n + 1]; for (int i = 1; i <= k; i++) { int curMax = Integer.MIN_VALUE; for (int j = 0; j < n; j++) { int temp = cur[j + 1]; cur[j + 1] = Math.max(Math.max(cur[j + 1], cur[j]), prices[j] + curMax); System.out.print(curMax + "|"); curMax = Math.max(curMax, temp - prices[j]); System.out.print(curMax + "\n"); } System.out.println(Arrays.toString(cur)); } return cur[n]; } /** * DP, bottom-up, O(kn) Time, O(kn) Space */ public int maxProfit(int k, int[] prices) { if (prices == null || prices.length < 2 || k == 0) { return 0; } int n = prices.length; int res = 0; if (k >= n / 2) { for (int i = 1; i < n; i++) { if (prices[i] > prices[i - 1]) { res += prices[i] - prices[i - 1]; } } return res; } int[][] dp = new int[k + 1][n + 1]; for (int i = 1; i <= k; i++) { int curMax = Integer.MIN_VALUE; for (int j = 0; j < n; j++) { dp[i][j + 1] = Math.max(Math.max(dp[i - 1][j + 1], dp[i][j]), prices[j] + curMax); curMax = Math.max(curMax, dp[i - 1][j] - prices[j]); } } return dp[k][n]; } }