[front end algorithm] the best time to buy and sell stocks, including handling charges -- greedy algorithm and dynamic programming implementation

Posted by tzzoug on Fri, 11 Feb 2022 16:41:13 +0100

Title Description

Given an integer array prices, where the i-th element represents the stock price on the i-th day; The integer fee represents the handling fee for trading stocks.

You can complete transactions indefinitely, but you need to pay a handling fee for each transaction. If you have bought a stock, you can't continue to buy it until you sell it.

Returns the maximum profit.

Note: a transaction here refers to the whole process of buying, holding and selling stocks. You only need to pay a handling fee for each transaction.

Example 1:

Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
 Output: 8
 Explanation: maximum profit:  
Buy here prices[0] = 1
 Sell here prices[3] = 8
 Buy here prices[4] = 4
 Sell here prices[5] = 9
 Total profit: ((8 - 1) - 2) + ((9 - 4) - 2) = 8
 Example 2:

Input: prices = [1,3,7,5,10,3], fee = 3
 Output: 6

Tips:

1 <= prices.length <= 5 * 104 1 <= prices[i] < 5 * 104 0 <= fee < 5 * 104

Source: LeetCode link: LeetCode CN COM / problems / be... [1] the copyright belongs to Lingkou network. For commercial reprint, please contact the official authorization, and for non-commercial reprint, please indicate the source.

Problem solving ideas

Idea 1: dynamic programming implementation

Dynamic programming Trilogy

  • Define dp meaning
    • Definition dp[n][2]:
    • N means there are two states on day n, holding or not holding
    • dp[i][0] the maximum profit obtained by not holding on day I;
    • dp[i][1] the maximum profit obtained by holding on day I; (tip: hold, not buy)
  • Define the state transition equation: For today's non holding, it can be transferred from two states: 1 Not yesterday; 2. Hold it yesterday, sell it today and pay the handling fee fee fee fee. Whichever is greater. For today's holding, it can be transferred from two states: 1 Also held yesterday; 2. Do not hold yesterday, buy today. Whichever is greater.
    • dp[i][1]=Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
    • dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
  • Initialize dp;
    • Not held: dp[0][0]=0;
    • Holding: dp[0][1]=-prices[0] (i.e. buying with price[0])

Since DP [n] [0] > DP [i] [1], the profit of not holding shares on the same day must be greater than that of holding shares on the same day, so return dp[len-1][0]

Spatiotemporal complexity

  • Time complexity: O(n), you can traverse it once.
  • Space complexity: O(n)

code

function maxProfit(prices: number[], fee: number): number {
    
    let len=prices.length;
     // define dp
     let dp=new Array(len);
     for(let i=0;i<len;i++){
         dp[i]=new Array(2).fill(0);
     }
     // init dp 
     dp[0][0]=0;
     dp[0][1]=-prices[0];
     for(let i=1;i<len;i++){
         dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]-fee);
         dp[i][1]=Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
     }
     console.log(dp);
    return dp[len-1][0]
};

optimization

Dimensionality reduction: during state transition, dp[i] will only be transferred from dp[i-1], so the first dimension can be removed:

Spatiotemporal complexity

  • Time complexity: O(n), you can traverse it once.
  • Space complexity: O(1)
 function maxProfit(prices: number[], fee: number): number {
    
    let len:number=prices.length;
     // define dp
     let dp=new Array(2);

     // init dp 
     dp[0]=0;
     dp[1]=-prices[0];
     for(let i=1;i<len;i++){
         let temp=dp[0]
         dp[0]=Math.max(dp[0],dp[1]+prices[i]-fee);
         dp[1]=Math.max(temp-prices[i],dp[1]);
     }
     console.log(dp);
    return dp[0]
};

Idea 2: greedy algorithm

  • Calculating the handling fee when buying can get a greedy method;
  • We define buy as: on the premise of maximizing benefits, when we have a stock in hand, then his buying price is the lowest.
    • profit=prices[i]-buy;
    • But at this time, our selling may not be the optimal solution. For example, the price continues to rise the next day;
    • Therefore, we can assume that there is a repudiation operation, assuming that there is a stock with a purchase price of prices[i],
    • Update buy to prices[i]:buy=prices[i];
    • If the price continues to rise the next day, we will get prices[i+1]-prices[i]. At this time, plus the income of prices[i]-buy of the previous day,
    • It can be seen from the above that it is equivalent to selling the next day without any operation: prices[i+1]-buy
    • Initialize to buy=prices[0]+fee;
    • If the current stock price [i] + fee < buy; Then we update the lowest purchase price buy;
    • If the current stock is larger than buy, we can sell it directly to make a profit
    • In other cases, it is not worth selling;

Spatiotemporal complexity

  • Time complexity: O(n), you can traverse it once.
  • Space complexity: O(1)
function maxProfit(prices: number[], fee: number): number {
  let len=prices.length;
  let buy=prices[0]+fee;
  let profit=0;
  for(let i=1;i<len;i++){
      if(prices[i]+fee<buy){
          buy=prices[i]+fee;
      }else if(prices[i]>buy){
          profit+=prices[i]-buy
          buy=prices[i]
      }
  }// end of for 
  return profit
};

reference material

[1]https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee: https://link.juejin.cn/?target=https%3A%2F%2Fleetcode-cn.com%2Fproblems%2Fbest-time-to-buy-and-sell-stock-with-transaction-fee