package com.interview.leetcode.application; /** * Created_By: stefanie * Date: 14-11-12 * Time: 下午8:54 * * Say you have an array prices[] for which the ith element is the price of a given stock on day i. * Design an algorithm to find the maximum profit. * * 1: You may complete only one transaction. {@link #oneTrans(int[])} * 2: You may complete multiple transactions. {@link #multiTrans(int[])} * 3: You may complete at most two transactions. {@link #oneOrTwoTrans(int[])} * * From LeetCode * https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-i/ * https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ * https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ * * Tricks: * 1. define a simplest and clear calculation method for the variable you interested (profit) * 2. transform the problem to a simpler question: * find a break point day i, make one transaction before day i and one after day i. * 3. keeping left and right sols, and using left and right to create whole solution. * 3. using dynamic programming to solve duplicate cases. */ public class BestTimetoBuyandSellStock { /** * You may complete only one transaction. O(N) * * Keep tracking min from beginning, at day i, the max profit could get is prices[i] - min. * */ public static int oneTrans(int[] prices){ if(prices.length < 1) return 0; int min = prices[0]; int profit = 0; for(int i = 1; i < prices.length; i++){ if(prices[i] < min) min = prices[i]; //tracking min else if(prices[i] - min > profit) profit = prices[i] - min; //calculate the profit and update max profit } return profit; } /** * You may complete multiple transactions. O(N) * * Scan the prices to find a buy time and sell time * buy time: the prices go up in the next day * sell time: the prices go down in the next day * profit is the sum of each transaction */ public static int multiTrans(int[] prices){ int maxProfit = 0; int buyPrice = -1; for(int i = 0; i < prices.length - 1; i++){ if(buyPrice == -1 && prices[i] < prices[i + 1]) { //found a time to buy buyPrice = prices[i]; } else if(buyPrice != -1 && prices[i] > prices[i + 1]){ //found a time to sell maxProfit += prices[i] - buyPrice; //add the profit of this transaction buyPrice = -1; } } if(buyPrice != -1) maxProfit += prices[prices.length - 1] - buyPrice; return maxProfit; } /** * You may complete at most two transactions. O(N) * * We need find a break point to have 2 transactions with max profit. * left[i] = the max profit could make before day i with one transaction * left[i] = Math.max(left[i-1], prices[i] - min) min is between 0 ~ i * right[i] = the max profit could make after day i with one transaction * right[i] = Math.max(right[i+1], max - prices[i]) max is between length - 1 ~ i * when day i is the break point, profit = left[i] + right[i]; */ public static int oneOrTwoTrans(int[] prices){ if(prices == null || prices.length == 0) return 0; int[] left = new int[prices.length]; int[] right = new int[prices.length]; left[0] = 0; int min = prices[0]; for(int i = 1; i < prices.length; i++){ //DP on the left part if(prices[i] < min) min = prices[i]; left[i] = Math.max(left[i - 1], prices[i] - min); } right[prices.length - 1] = 0; int max = prices[prices.length - 1]; for(int i = prices.length - 2; i >= 0; i--){ //DP on the right part if(prices[i] > max) max = prices[i]; right[i] = Math.max(right[i + 1], max - prices[i]); } int profit = 0; for(int i = 0; i < prices.length; i++){ //find the max profit profit = Math.max(profit, left[i] + right[i]); } return profit; } }