Jb Tak Fodega Nhi 🎯 Tb Tk Chodega
Nhi 📚 (MAANG)
DPL36 Best Time to Buy and Sell Stock II
We are given an array Arr[] of length n.
It represents the price of a stock on
‘n’
days. The following guidelines need to
be followed:
Find and return the maximum profit you can achieve.
Every day, we will have two choices, either to do nothing and move to the next day or to buy/sell (based on the last transaction) and find out the profit. Therefore we need to generate all the choices in order to compare the profit. As we need to try out all the possible choices, we will use recursion.
Recursice Approch
Again here we follow the out Standerad Patter that we learned in the Dynamic Programming Introduction. How to Write Recursion
Steps to form the Recursive SolutionStep 1: Express the problem in terms of indexes.
Step 2: Try out all possible choices at a given index.
Every day, we have two choices
If we can buy the stock on a particular day, we have two options
Case 2: When buy == 1, we can sell the stock.
Agin we have If we can buy the stock on a particular day, we have two options
The figure below gives us the Summary
Step 3: Return the Maximum
Base Cases If ind==n, it means we have finished trading on all days, and there is no more money that we can get, therefore we simply return 0. ("Does.t Matter if we Have Some Stocks are Remaing not at the End Profit will we 0")
class Solution: def RecursionApproch(self, prices,index,n,decisionFlag): # Base Case if index == n: return 0 maxProfit = 0 if decisionFlag == 1: # as similar to take and notTake Concepts buyTheStock = -prices[index] + self.RecursionApproch(prices,index+1,n,0) notBuyTheStock = 0 + self.RecursionApproch(prices,index+1,n,1) maxProfit = max(buyTheStock,notBuyTheStock) else: shellTheStock = prices[index] + self.RecursionApproch(prices, index + 1, n, 1) notSellTheStock = 0 + self.RecursionApproch(prices, index + 1, n, 0) maxProfit = max(shellTheStock, notSellTheStock) return maxProfit def maxProfit(self, prices): n = len(prices) decisionFlag = 1 return self.RecursionApproch(prices,0,n,decisionFlag) ans = Solution() prices = [7,1,5,3,6,4] print(ans.maxProfit(prices))
Time & Space Complexity
Time Complexity: O(2^N)Reason: Exponential Time we find out the all the Possible Path
Space Complexity: O(N)
Reason: We are using a recursion stack space(O(N))
Memoization Approch
If we Observe in the recursion tree, we will observe a many number of overlapping subproblems. Therefore the recursive solution can be memoized for to reduce the time complexity.
Steps to convert Recursive code to memoization solution:class Solution: def MemoizationApproch(self, prices,index,n,decisionFlag,dp): # Base Case if index == n: return 0 if dp[index][decisionFlag] != -1: return dp[index][decisionFlag] maxProfit = 0 if decisionFlag == 1: # as similar to take and notTake Concepts buyTheStock = -prices[index] + self.MemoizationApproch(prices,index+1,n,0,dp) notBuyTheStock = 0 + self.MemoizationApproch(prices,index+1,n,1,dp) maxProfit = max(buyTheStock,notBuyTheStock) else: shellTheStock = prices[index] + self.MemoizationApproch(prices, index + 1, n, 1,dp) notSellTheStock = 0 + self.MemoizationApproch(prices, index + 1, n, 0,dp) maxProfit = max(shellTheStock, notSellTheStock) dp[index][decisionFlag] = maxProfit # we can also return maxProfit its also give the correct answer return dp[index][decisionFlag] def maxProfit(self, prices): n = len(prices) decisionFlag = 1 dp = [] for _ in range(n): arr = [-1] * (2) dp.append(arr) return self.MemoizationApproch(prices,0,n,decisionFlag,dp) ans = Solution() prices = [7,1,5,3,6,4] print(ans.maxProfit(prices))
Time & Space Complexity
Time Complexity:O(N*2)Reason: TThere are N*2 states therefore at max ‘N*2’ new problems will be solved and we are running a for loop for ‘N’ times to calculate the total sum
Space Complexity: O(N*2) + O(N)
Reason: We are using a recursion stack space(O(N)) and a 2D array ( O(N*2)).
Tabulation Approch
Tabulation is a ‘bottom-up’ approach where we start from the base case and reach the final answer that we want and Memoization is the Top-down Approch.In Tabulation Approch We Just Creat a DP Array Same as Memoization and Simply Convert the Recurance Relation into the form of the Looping
VVVV Important Point: Tabulation Approch is Always 1-Based Indexing Always RememberSteps to convert Recursive Solution to Tabulation one.
class Solution: def TabulationApproch(self, prices,n,dp): # Base Case dp[n][0] = 0 dp[n][1] = 0 for index in range(n-1,-1,-1): for decisionFlag in range(2): maxProfit = 0 if decisionFlag == 1: # as similar to take and notTake Concepts buyTheStock = -prices[index] + dp[index+1][0] notBuyTheStock = 0 + dp[index+1][1] maxProfit = max(buyTheStock,notBuyTheStock) else: shellTheStock = prices[index] + dp[index+1][1] notSellTheStock = 0 + dp[index+1][0] maxProfit = max(shellTheStock, notSellTheStock) dp[index][decisionFlag] = maxProfit # we can also return maxProfit its also give the correct answer print(dp) return dp[0][1] def maxProfit(self, prices): n = len(prices) decisionFlag = 1 dp = [] for _ in range(n+1): arr = [0] * (2) dp.append(arr) print(dp) return self.TabulationApproch(prices,n,dp) ans = Solution() prices = [7,1,5,3,6,4] print(ans.maxProfit(prices))
Time & Space Complexity
Time Complexity: O(N*2)Reason: There are two nested loops that account for O(N*2) complexity.
Space Complexity: O(N*2)
Reason: We are using an external array of size ‘N*2’. Stack Space is eliminated.
Space Optimization
If we closelly Observed if any Tabulation Approch we used the Some Limited Stuff like: dp[ind][buy] = max(dp[ind+1][buy] , max( dp[ind+1][!buy])) for the finding the our ans then definetly here Spaced Optimization is Possible in that types of Problems. Always Remember
Golden Rule
class Solution: def SpaceOptimizationApproch(self, prices,n,prev,curr): # Base Case prev[0] = 0 prev[1] = 0 for indx in range(n-1,-1,-1): for decisionFlag in range(2): maxProfit = 0 if decisionFlag == 1: # as similar to take and notTake Concepts buyTheStock = -prices[indx] + prev[0] notBuyTheStock = 0 + prev[1] maxProfit = max(buyTheStock,notBuyTheStock) else: shellTheStock = prices[indx] + prev[1] notSellTheStock = 0 + prev[0] maxProfit = max(shellTheStock, notSellTheStock) curr[decisionFlag] = maxProfit prev = curr # we can also return maxProfit its also give the correct answer return prev[1] def maxProfit(self, prices): n = len(prices) prev = [0, 0] curr = [0, 0] return self.SpaceOptimizationApproch(prices,n,prev,curr) ans = Solution() prices = [1,2,3,4,5,6,7] print(ans.maxProfit(prices))
Time & Space Complexity
Time Complexity: O(N*2)Reason: There are two nested loops that account for O(N*2) complexity
Space Complexity: O(1)
Reason: We are using an external array of size ‘2’.
Most Space Optimization
If we observe very carefully, we only require two variables, namely prices[index + 1] and prices[index], for calculating the current day's profit. That's it; this is the crux of the question. We just use these two entities, and with each iteration, we update the profit.
class Solution: def MostSpaceOptimizationApproch(self, prices,n): profit = 0 for index in range(n-1): currProfit = prices[index + 1] - prices[index] if currProfit > 0: profit += currProfit return profit def maxProfit(self, prices): n = len(prices) return self.MostSpaceOptimizationApproch(prices,n) ans = Solution() prices = [1,2,3,4,5,6,7] print(ans.maxProfit(prices))
Time & Space Complexity
Time Complexity: O(N)Reason: Linear Iteration we used only
Space Complexity: O(1)
Reason: We are using just 2 variables of the calculating the Profte.