The topic of stock trading algorithm can be said to be a very interesting existence in the basic algorithm. A slight change in the subject may lead to a completely different view of the problem. Don't say much. Let's have a look
Given an array price, its second I elements prices[i] represents the price of a given stock on day I. You can only choose to buy this stock one day and sell it on a different day in the future. Design an algorithm to calculate the maximum profit you can make. Return the maximum profit you can make from this transaction. If you can't make any profit, return 0.
Input: [7,1,5,3,6,4]
Output: 5
Train of thought analysis: there is a certain maximum profit for each item of the array. This is obtained by subtracting the previous minimum value from the current value. Of course, this kind of stock buying method is certainly impossible, isn't it. Therefore, two variables are used to dynamically represent the minimum minprice and maximum profit max respectively. Is it OK to traverse the array?
var maxProfit = function(prices) { let minprice=Number.MAX_SAFE_INTEGER let max=0 for(let i=0;i<prices.length;i++){ if(prices[i]<minprice){ minprice=prices[i] }else if(prices[i]-minprice>max){ max=prices[i]-minprice } } return max };
This is actually similar to the idea of double pointers.
Suppose you can complete the transaction indefinitely, but you need to pay a handling fee fee fee for each transaction. And if you have bought a stock, you can't continue to buy it until you sell it.
It is easy to think of the greedy algorithm. As long as there is a surplus after the profit of buying and selling minus fee, I will make a profit. In fact, this idea may not bring the global optimal solution, because if it increases the next day, I have to pay a handling fee for buying and selling. So we have to judge whether it is still increasing the next day.
A clever idea can be adopted: hand over the handling fee when buying, not selling. Maintain a buy variable as price [i] + fee, traverse the array and update the buy to the minimum. In addition, if the price [i] is greater than buy, you can make a profit. However, in order to prevent an increasing price [i], buy is updated to price [i], instead of price [i] + fee.
var maxProfit = function(prices, fee) { let buy=prices[0]+fee let max=0 for(let i=1;i<prices.length;i++){ if(prices[i]+fee<buy){ buy=prices[i]+fee }else if(prices[i]>buy){ max+=prices[i]-buy //Considering that there is an increase in prices[i] buy=prices[i] } } return max }
In addition, it can also be solved by dynamic programming. By analyzing the status, we can know that there are only two statuses on day i+1, i.e. stocks on hand and no stocks on hand, so we define a two-dimensional array. dp[i][0] represents the maximum return when there is no stock in hand. dp[i][1] represents the maximum return when there are stocks in hand.
Then the recursive equation is easy to write. dp[i][0] may be because dp[i-1][0], or dp[i][0]+prices[i]-fee sold the stock. Whichever is greater.
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]-fee)
Similarly, we can get:
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i])
If the boundary condition is dp[0][0]=0,dp[0][1]=-prices[0], the code can be obtained:
var maxProfit = function(prices, fee) { let dp=new Array(prices.length).fill(0).map(item=>new Array(2).fill(0)) dp[0][0]=0,dp[0][1]=-prices[0] for(let i=1;i<prices.length;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][1],dp[i-1][0]-prices[i]) } return Math.max(dp[prices.length-1][0],dp[prices.length-1][1]) };
ok, continue to revise the title... What if you don't consider the handling fee? That is, as long as there is a positive difference between two adjacent items, you can buy and sell. At this time, the local optimal solution is the overall optimal solution, a serious greedy algorithm. Just traverse the array and compare the relationship between the difference before and after and 0.
var maxProfit = function(prices){ let result=0 for(let i=1;i<prices.length;i++){ result+=Math.max(0,prices[i]-prices[i-1]) } return result }
There is also a variant. What about adding a one-day freezing period after selling out the stock?
I directly choose dynamic programming. From the analysis, we can see that there are only three states in each day. The first state is holding stocks (represented by 0), the second state is in the frozen period (represented by 1), and the third state is non holding stocks outside the frozen period (represented by 2). Therefore, DP [i] [0], DP [i] [1] and DP [i] [2] represent the maximum profits under the three states respectively.
By analyzing the equation of state:
dp[i][0] = Math.max(dp[i-1][0] , dp[i-1][2]-prices[i])
dp[i][1] = dp[i-1][0] , prices[i]
dp[i][2] = Math.max(dp[i-1][2] , dp[i-1][1])
The third step is to determine the initial state:
dp[0][0] = -prices[0],dp[0][0] = 0,dp[0][0] = 0
Upper Code:
var maxProfit = function(prices) { let dp=new Array(prices.length).fill(0).map(item=>new Array(3).fill(0)) dp[0][0]=-prices[0] dp[0][1]=0 dp[0][2]=0 for(let i=1;i<prices.length;i++){ //Holding shares dp[i][0]=Math.max(dp[i-1][0],dp[i-1][2]-prices[i]) //It is in the frozen period and does not hold shares dp[i][1]=dp[i-1][0]+prices[i] //Not in the freezing period, not holding shares dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]) } return Math.max(dp[prices.length-1][1],dp[prices.length-1][2]) };
The above is the js sharing of stock topics, greedy, dynamic programming, and the idea of similar double pointers (strive to traverse the array at one time). Carefully taste or have a lasting appeal, so now there is a question, can all algorithms finally summarize a meta algorithm? Like the unified theory in cosmic physics? To be explored.