package com.freetymekiyan.algorithms.level.easy; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Say you have an array for which the ith element is the price of a given stock on day i. * <p> * If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design * an algorithm to find the maximum profit. * <p> * Example 1: * Input: [7, 1, 5, 3, 6, 4] * Output: 5 * <p> * max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price) * Example 2: * Input: [7, 6, 4, 3, 1] * Output: 0 * <p> * In this case, no transaction is done, i.e. max profit = 0. * Company Tags: Amazon, Microsoft, Bloomberg, Uber, Facebook * Tags: Array, Dynamic Programming * Similar Problems: (M) Maximum Subarray, (M) Best Time to Buy and Sell Stock II, (H) Best Time to Buy and Sell Stock * III, (H) Best Time to Buy and Sell Stock IV, (M) Best Time to Buy and Sell Stock with Cooldown */ public class BestTimeToBuyAndSellStock { private BestTimeToBuyAndSellStock b; /** * DP. Bottom-up. Optimized. O(n) Time, O(1) Space. * Maximum profit is the maximum price - minimum price. * So loop from second day to last day, track min price and max profit. * Suppose max profit of ith day is P[i]. * If price[i] > price[i-1], then P[i] may be larger than P[i-1]. Update it. * If price[i] <= price[i-1], then P[i] cannot be larger. But there may be a new minimum price. * Update min price that can be used for later iterations. * Base case: * Max profit is 0. Min price is the first day's price. */ public int maxProfit(int[] prices) { if (prices == null || prices.length < 2) { // Need at least 2 days to make profit. return 0; } int max = 0; // Max profit. int min = prices[0]; // Min price of previous days. for (int i = 1; i < prices.length; i++) { if (prices[i] > prices[i - 1]) { // Maximum price may update. max = Math.max(max, prices[i] - min); // Update max profit. } else { min = Math.min(min, prices[i]); // Update min. } } return max; } /** * DP. Bottom-up. O(n) Time. O(n) Space. * Keep track of minimum price of the stock. * Keep track of the maximum profit before today. * Get the maximum profit of today, and compare with previous maximum. * Update maximum if today's profit is larger. * Stop until the array is fully traversed. * O(n) Time, O(n) Space. */ public int maxProfitB(int[] prices) { if (prices == null || prices.length < 2) { return 0; // need at least 2 days } int min = prices[0]; int max = 0; int len = prices.length; int[] history = new int[len]; for (int i = 0; i < len - 1; i++) { min = min < prices[i] ? min : prices[i]; if (i > 0) { // skip first day history[i] = Math.max(history[i - 1], prices[i] - min); max = history[i] > max ? history[i] : max; } } return max; } @Before public void setUp() { b = new BestTimeToBuyAndSellStock(); } @Test public void testExamples() { int[] prices = {1, 4, 2}; Assert.assertEquals(3, b.maxProfit(prices)); Assert.assertEquals(3, b.maxProfitB(prices)); } @After public void tearDown() { b = null; } }