LeetCode 121 - Best Time to Buy and Sell Stock


Say you have an array for which the ith element is the price of a given stock on day i.

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.

Example
Given array [3,2,3,1,2], return 1.
A smart way is to record the minimum buy-in price before day i , and the maximum profit by selling the stock on day i would be their difference. 
public int maxProfit(int[] prices) {
        if(prices==null || prices.length==0)
            return 0;
        int lowestBuyInPrice = prices[0];   // Lowest buy-in price up to now
        int maximumProfit = 0;              // Maximum profit up to now
        for (int i = 1; i < prices.length; i++) {
            // Update the maximum profit if buying the stock with the lowest price up to now and
            // selling it in day i makes greater profit
            maximumProfit = Math.max(maximumProfit, prices[i]-lowestBuyInPrice);
            // Update the lowest price if the price in day i is smaller than those in earlier days
            lowestBuyInPrice = Math.min(lowestBuyInPrice, prices[i]);
        }
        return maximumProfit;
    }
https://xuezhashuati.blogspot.com/2017/04/lintcode-149-best-time-to-buy-and-sell.html
遍历数组,并且维护一个最小股价和一个最大利润。
如果当前股价 - 最小股价 > 最大利润,那么我们更新最大利润。
最小股价为当前股价和之前最小股价的较小值。
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = Integer.MIN_VALUE;
        
        for (int i = 0; i < prices.length; i++) {
            int currPrice = prices[i];
            int currProfit = currPrice - minPrice;
            minPrice = Math.min(minPrice, currPrice);
            maxProfit = Math.max(maxProfit, currPrice - minPrice);
        }
        
        return maxProfit;
    }
https://leetcode.com/discuss/9212/a-o-1-n-solution
public int maxProfit(int[] prices) { if(prices==null||prices.length<=1){ return 0; } int min=prices[0]; int profit=0; for(int i=1;i<prices.length;i++){ min = Math.min(min,prices[i]); profit = Math.max(profit, prices[i]-min); } return profit; }
X.
The logic to solve this problem is same as "max subarray problem" using Kadane's Algorithm. Since no body has mentioned this so far, I thought it's a good thing for everybody to know.
All the straight forward solution should work, but if the interviewer twists the question slightly by giving the difference array of prices, Ex: for {1, 7, 4, 11}, if he gives {0, 6, -3, 7}, you might end up being confused.
Here, the logic is to calculate the difference (maxCur += prices[i] - prices[i-1]) of the original array, and find a contiguous subarray giving maximum profit. If the difference falls below 0, reset it to zero.
    public int maxProfit(int[] prices) {
        int maxCur = 0, maxSoFar = 0;
        for(int i = 1; i < prices.length; i++) {
            maxCur = Math.max(0, maxCur += prices[i] - prices[i-1]);
            maxSoFar = Math.max(maxCur, maxSoFar);
        }
        return maxSoFar;
    }
*maxCur = current maximum value
*maxSoFar = maximum value found so far
Related:http://www.geeksforgeeks.org/maximum-difference-between-two-elements/
Given an array arr[] of integers, find out the difference between any two elements such that larger element appears after the smaller number in arr[].
Examples: If array is [2, 3, 10, 6, 4, 8, 1] then returned value should be 8 (Diff between 10 and 2). If array is [ 7, 9, 5, 6, 3, 2 ] then returned value should be 2 (Diff between 7 and 9)


In this method, instead of taking difference of the picked element with every other element, we take the difference with the minimum element found so far. So we need to keep track of 2 things:
1) Maximum difference found so far (max_diff).
2) Minimum number visited so far (min_element).
int maxDiff(int arr[], int arr_size)
{
  int max_diff = arr[1] - arr[0];
  int min_element = arr[0];
  int i;
  for(i = 1; i < arr_size; i++)
  {      
    if (arr[i] - min_element > max_diff)                              
      max_diff = arr[i] - min_element;
    if (arr[i] < min_element)
         min_element = arr[i];                    
  }
  return max_diff;
Like min element, we can also keep track of max element from right side. See below code suggested by Katamaran
int maxDiff(int arr[], int n)
{
    int maxDiff = -1; // Initialize Result
    int maxRight = arr[n-1]; // Initialize max element from right side
    for (int i = n-2; i >= 0; i--)
    {
        if (arr[i] > maxRight)
            maxRight = arr[i];
        else
        {
            int diff = maxRight - arr[i];
            if (diff > maxDiff)
            {
                maxDiff = diff;
            }
        }
    }
    return maxDiff;
}
X. 
First find the difference between the adjacent elements of the array and store all differences in an auxiliary array diff[] of size n-1. Now this problems turns into finding the maximum sum subarray of this difference array.
int maxDiff(int arr[], int n)
{
    // Create a diff array of size n-1. The array will hold
    //  the difference of adjacent elements
    int diff[n-1];
    for (int i=0; i < n-1; i++)
        diff[i] = arr[i+1] - arr[i];
    // Now find the maximum sum subarray in diff array
    int max_diff = diff[0];
    for (int i=1; i<n-1; i++)
    {
        if (diff[i-1] > 0)
            diff[i] += diff[i-1];
        if (max_diff < diff[i])
            max_diff = diff[i];
    }
    return max_diff;
}
We can modify the above method to work in O(1) extra space. Instead of creating an auxiliary array, we can calculate diff and max sum in same loop.
int maxDiff (int arr[], int n)
{
    // Initialize diff, current sum and max sum
    int diff = arr[1]-arr[0];
    int curr_sum = diff;
    int max_sum = curr_sum;
    for(int i=1; i<n-1; i++)
    {
        // Calculate current diff
        diff = arr[i+1]-arr[i];
        // Calculate current sum
        if (curr_sum > 0)
           curr_sum += diff;
        else
           curr_sum = diff;
        // Update max sum, if needed
        if (curr_sum > max_sum)
           max_sum = curr_sum;
    }
    return max_sum;
}

Brute Force:
int maxDiff(int arr[], int arr_size)
{    
  int max_diff = arr[1] - arr[0];
  int i, j;
  for(i = 0; i < arr_size; i++)
  {
    for(j = i+1; j < arr_size; j++)
    {       
      if(arr[j] - arr[i] > max_diff)  
         max_diff = arr[j] - arr[i];
    }   
  }         
  return max_diff;
http://blog.csdn.net/u014688145/article/details/70992371
它的每一个历史最低点都会向后找【所有】历史最高点去比较(你也可以看作是跟每个向后的历史值去比较,只要维护一个maxProfit即可),所以它可以逆向思考,也就是说,遍历到当前点,我们可以向前去比较历史最低点,不断更新maxProfit,遍历结束总能找到正确值。

但需要明确一点,之所以可以这样做,无非两点,之前的信息我们可记录(维护一个最小的minPrice变量),其次遍历的后向性所带来的好处,由问题本身决定(股票一定是先买后卖)。
public int maxProfit(int[] prices) { int minprice = Integer.MAX_VALUE; int maxprofit = 0; for (int i =0;i<prices.length;i++){ if (prices[i] < minprice){ minprice = prices[i]; }else if (prices[i]-minprice > maxprofit){ maxprofit = prices[i] - minprice; } } return maxprofit; }

这是一种思路,带来了O(n)的解决方案。再来看一种解决方案,核心思想如下: 
1. 卖的同时可以瞬间买进。(多个操作可以看成一个操作) 
2. 没钱的情况下,可以看作向别人借钱(记忆)
虽然代码形式和上一种不太一样,但它们本质上是一种形式,可以互相转换。但该代码的好处在于它更加亲民接地气。更符合人的认知,buy可以看作是借钱的过程,而max是为了搜索价格最低的买点,sell是维护了最大的利益,而且很重要的一点它是势能突破函数,高一点就向上顶一下,非常形象。buy和sell同时操作price,这是另外一个神奇的地方,因为核心思想提到,卖的同时可以买进,如果只存在一个元素,该操作返回的sell还是为0,可以看作无操作,符合边界条件
public int maxProfit(int[] prices) { int buy = Integer.MIN_VALUE; int sell = 0; for (int price : prices){ buy = Math.max(buy, -price); sell = Math.max(sell, buy + price); } return sell; }

它还有另外一种解法,它的买卖同时更加形象。利用的是势能不断增加,突破max就更新max,当价格下降时,势能降低,但最低不超过0。(sum减到0就停止更新)

就从整个prices的价格走势来看,只要有上升的情况,我们就可以使用sum += prices[i]-prices[i-1]来不断累计(卖的瞬间可以立马买进,多个操作的组合可以看成一个操作)。而当价格走势下降时,处于亏损状态,sum不断减小,而不会取负值。(此处是不会影响max的)。所以维持一个sum很关键,简单总结下,它是个变态势能累积函数(不公平势能累积),上升趋势总能被更新,而下降趋势,下降到0时,不记录势能sum中。好处是把上升趋势的最低点拔高到0势能点,从而可以不断更新较大的max。
public int maxProfit(int[] prices) { int sum = 0; int max = 0; for (int i = 1; i < prices.length;i++){ sum = Math.max(0, sum += prices[i]-prices[i-1]); max = Math.max(max, sum); } return max; }
Read full article from LeetCode - Best Time to Buy and Sell Stock | Darren's Blog

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts