【leetcode】121. Best Time to Buy and Sell Stock && 53. Maximum Subarray 解题报告:用DP的思维去看待问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dpengwang/article/details/85911311

121. Best Time to Buy and Sell Stock
在这里插入图片描述
买卖股票的最佳时机基础版本,只能交易一次,求最大利润。
思路一:非算法思维
要求最大利润,肯定是低价买入高价卖出,我们只要获取全局最小值和全局最大值,并且最小值出现在最大值前面, 那么这就是我们要求的最大值。
我们只需要用一个变量记录之前出现过的最小值,然后用当天的价格减去这个最小值就是在改天之前的最小值买入当天卖出的利润,遍历一遍即可获得求得最大值。

class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if len(prices)==0:
            return 0
        miner = prices[0]
        res = 0
        for i in range(1,len(prices)):
            res = max(res,prices[i]-miner)
            miner = min(miner, prices[i])
        return res

思路二:DP思维
思路一可以解决问题,但是感觉没有个章法,我们希望看到的是这一类问题都能用一个差不多的思想去解决他们。
考虑DP,DP的关键是求出递推方程,如果能求出递推方法,那么就是DP问题。
考虑第i天的卖出的利润,第i天,可以看做是第i-1天买入,第i天卖出并且加上第i-1天的利润,即
profit[i] = max(prices[i]-prices[i-1]+profit[i-1],0)
求max操作也很好理解,如果当天卖出的利润为负,那么还不如不卖,不卖的利润为0.
也正是因为求了与0的max,对于利润累加才会在价格单增的时候累计,在负利润的时候重置,保证了利润最大化。
比如prices = [2,0,1,2],利润在i=1的时候置0,后面两天利润都是累加起来的,因为是单增序列,profit[i] = max(prices[i]-prices[i-1]+profit[i-1],0)可以保证利润行情好的时候(即价格上升)利润对应着上升

class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        res =0
        if len(prices) ==0:
            return 0
        dp = [0 for i in range(len(prices))]
        for i in range(1,len(prices)):
            dp[i] = max(0,prices[i]-prices[i-1]+dp[i-1])
            res = max(res,dp[i])
        return res

53. Maximum Subarray
在这里插入图片描述
求最大子序列和,这道题跟上一题有异曲同工之妙,都可以用DP的思维去解决,也可以不用Dp的思维。
思路1
当比遍历到第i个节点时,用curr_sum记录前面子序列的最大和,如果curr_sum小于0,那么更新curr_sumnums[i],因为负数加a肯定是小于a的。否则,更新curr_sumcurr_sum +nums[i],因为非负数数加a肯定是大于等于a的。记录其最大值即可

class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = nums[0]
        curr_sum = nums[0]
        for i in range(1,len(nums)):
            if curr_sum < 0:
                curr_sum = nums[i]
            else:
                curr_sum = curr_sum +nums[i]
            res = max(res, curr_sum)
        return res

思路二:DP思想
考虑第i个节点,研究的问题是包含第i个节点并且往前的最大子序列和为dp[i],那么dp[i]的值取决于dp[i-1],如果dp[i-1]<0,那么dp[i] = nums[i],否则等于dp[i-1]+nums[i]

class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = [0 for i in range(len(nums))]
        dp[0] = nums[0]
        res = dp[0]
        for i in range(1,len(nums)):
            dp[i] = max(dp[i-1],0) +nums[i]
            res = max(res,dp[i])
        return res            

总结:一般题目中需要记录历史最大或者最小,并且动态的更新当前值的,可能可以用DP的方法去做,DP的好处在于可以用递推方程简化很多if else逻辑,然思路更清晰。代码也更简洁

猜你喜欢

转载自blog.csdn.net/dpengwang/article/details/85911311