力扣Day32(2.21)| 第九章 贪心算法(无思路立马看答案,不然浪费时间) (122.买卖股票的最佳时机II 55. 跳跃游戏 45. 跳跃游戏 II☆☆☆☆)

题一:122.买卖股票的最佳时机II

链接

题目链接:
视频链接:
文章链接:

视频总结

关键点

编程思路

Me:
  1. 初步思路参考最大子数组和,借用连续和的方法,当指针为i时,判断n[i+1]-n[i],大于零的时候说明i处适合买不适合卖,也就是未来会涨。小于零说明未来会跌,所以当前需要卖掉,为零时保持原来的状态
卡尔:

力扣实战

思路一:贪心(yes)

 class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 贪心思想:借鉴最大子数组和那一题连续和的思想,连续和定义为未来价格减去当前价格,表示预知未来的涨和跌,涨的时候把收益累加,移动指针表示卖出,未来跌的时候,移动指针表示买入操作进行抄底
        res = 0
        day = len(prices)
        i=0
        while i<day-1:
            future=prices[i+1]-prices[i]
            if future>0:
                res+=future
            i+=1
        return res
        
# 反思1:
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 贪心思想:巧妙写法
        res = 0
        day = len(prices)
        for i in range(day-1):
            res+=max(0,prices[i+1]-prices[i])
        return res


思路二:动态规划

	#超时法,二维dp数组
 class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 动态规划:每天都有两个状态买或者卖,定义其最大收益,找到和历史数据的关系
        day = len(prices)
        dp = [[0,0]]	#第0天,买入和卖出收益都是0
        for i in range(1,day):
            dp.append([0,0])
            dp[i][0]=dp[i-1][1]	#为0表示买入,为1表示卖出;某天买入的收益,和前一天卖出的收益一样
            for j in range(i+1):    #若在第i天卖出,则前面的每一天都可能是买入日,都需要考虑
                dp[i][1]=max(dp[j][0]+prices[i]-prices[j],dp[i][1])	#这里和自身比,是因为从0遍历到i有很多次这个值的迭代
        return max(dp[-1][0],dp[-1][1])

# 一维dp数组,和贪心思路很像
  class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 动态规划:dp[i]定义为第i天的最大收益,因为可以多次交易,则最好最长持有天数不超过一天,在超过一天时,只有每天都涨才能保持最高收益,若区间有跌落,则非最大收益。转化为连续最大和问题
        day = len(prices)
        dp = [0]*(day)
        for i in range(1,day):
            #,若第i天买入,则第i天收益和第i-1天一样;若第I天卖出,则第i天的收益为i-1天最大收益加上最后一天收益
            dp[i]=max(dp[i-1],dp[i-1]+prices[i]-prices[i-1])    #和贪心非常像了  
        return dp[-1]

	#dp第三种理解!!二维dp矩阵也可以一个for循环拿下,厉害!
	class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 动态规划:
        #dp[i][0]表示第i天持有股票时,手头的现金(第i-1天可能持有,若没,则说明第i天买入了)
        #dp[i][1]表示第i天没持有股票时手头的现金(若第i-1天持有了,说明第i天卖了,若没持有,说明卖出还在前面)
        #则最后的最大收益手上一定没有持有股票,也就是dp[-1][1]
        dp = [[0,0]]
        dp[0][0]-=prices[0]     #表示若第一天就持有,说明花钱买了股票,则手头的钱是负的
        for i in range(1,len(prices)):
            dp.append([0,0])
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i])
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i])
        return dp[-1][1]

题二:55. 跳跃游戏

链接

题目链接:
视频链接:
文章链接:

视频总结

关键点

  1. 定义了一个指针用于记录最大覆盖范围,非常巧妙,在遍历往覆盖范围的路上,若最后覆盖范围可以到达终点,则说明可以到达重点,否则不可以

编程思路

卡尔:

在这里插入图片描述

力扣实战

思路一:

 class Solution:
    def canJump(self, nums: List[int]) -> bool:
        #贪心策略:若全为正数肯定能跳到,所以只需判断每个为零的地方能不能跳过,而零处是否可以跳过,取决于之前的数字要
        #足够越过零,所以遇到零就需要往前遍历,会超时吗?
        #麻辣个鸡,老六题,一个元素的情况,首为零,尾为零的情况都要考虑
        length = len(nums)
        if length==1:	#若长度为1,无论是否为零都可以
            return True
        if nums[0]==0:	#若长度不唯一且首为零,则一定不行
            return False
        
        for i in range(length-1):
            if nums[i]==0:
                for j in range(i-1,-1,-1):
                    if nums[j]>i-j:
                        break
                    elif j ==0 and nums[j]<=i:   # 若是遍历到开头还是跳不过去,则说明挑不到结尾
                        return False
        if nums[-1]==0:	#若末尾为零,单独考虑
            for j in range(length-2,-1,-1):
                    if nums[j]>=i-j:
                        break
                    elif j ==0 and nums[j]<=length-1:   # 若是遍历到开头还是跳不过去,则说明挑不到结尾
                        return False
            
        return True
        
# 反思1:

思路二:

 # python不支持动态修改for循环中变量,使用while循环代替
 class Solution:
    def canJump(self, nums: List[int]) -> bool:
        cover = 0
        if len(nums) == 1: 
        	return True
        i = 0
        # python不支持动态修改for循环中变量,使用while循环代替
        while i <= cover:
            cover = max(i + nums[i], cover)
            if cover >= len(nums) - 1: 
            	return True
            i += 1
        return False

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        cover = 0
        if len(nums) == 1: 
        	return True
        for i in range(len(nums)):
            if i <= cover:
                cover = max(i + nums[i], cover)
                if cover >= len(nums) - 1: 
                	return True
        return False

文档总结

1.  python不支持动态修改for循环中变量,使用while循环代替

题三:45. 跳跃游戏 II☆☆☆☆

链接

题目链接:
视频链接:
文章链接:

视频总结

关键点

  1. 贪心思路:每一步尽可能的增加覆盖范围
  2. 且每一步走到头时,记录下可以延伸的最大范围

编程思路

卡尔:

在这里插入图片描述

力扣实战

思路一:贪心版本一

 class Solution:
    def jump(self, nums: List[int]) -> int:
        #延续上题覆盖距离的思路,不过本题需要两个,一个是当前的最远距离,一个是下一步的最远距离
        if len(nums)==1:
            return 0
        cur,nex = 0,0	#cur用来记录当前的res步数时,可以到达的最远处,若当前可以覆盖到末尾,则直接返回当
        res = 0	#前的步数res,如果覆盖不到结尾,说明还需要走下一步,而下一步的起点就是cur范围里的任意一个
        for i in range(len(nums)):	#为使每一步尽可能的远,则用nex记录cur范围内可以达到的最远的地方,若是走到cur还没有到尽头,说明需要走下一步
            nex = max(nums[i]+i,nex)    #i一直往前走,直到当前i能走到的极限,期间记录下一步达到的最远距离,记为nex
            if i == cur:    #走到i的索引的尽头
                if cur <len(nums)-1:
                    cur =nex
                    res+=1
                    if cur >= len(nums)-1:
                        break
                else:
                    break
        return res

        
# 反思1:

思路二:贪心版本二

 # 贪心版本二
class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        curDistance, nextDistance = 0, 0
        step = 0
        for i in range(len(nums)-1):	#此处减一是关键,如果走到倒数第二个还没到cur的末尾,说明已经到列表末尾了,若走到倒数第二个已经是cur的末尾,那么后面任意走一步就可以到终点,只需res+=1即可
            nextDistance = max(nextDistance, nums[i]+i)
            if i == curDistance:	
                curDistance = nextDistance
                step += 1
        return step

思路三 动态规划

# 动态规划做法:本题的状态转移方程找的是i+j处和其他信息的关系,比较特别;通常是锚定dp[i],观察他由哪些部分组成,这题是立足于dp[i],知道他的覆盖范围,范围内的都是一步就到达,然后移动i节点,分层更新dp[i],每次取最小的状态值。
class Solution: 
    def jump(self, nums: List[int]) -> int:
        result = [10**4+1]*len(nums)	#表示走到索引i处的小步数,最后返回result[-1]
        result[0]=0
        for i in range(len(nums)):
            for j in range(nums[i]+1):	#相当于j一直走到cur的尽头
                if i+j<len(nums): 	#索引的和就是第i个节点能够走到的距离,此处也就是没走到头时
                #更新走到i+j最小的距离,初始为最大步数,更新为result[i]+1,因为当前点位于位置i,加一表示cur范围内,从i处都可以一步到达
                	result[i+j]=min(result[i+j],result[i]+1)
        #print(result) #打印数组
        return result[-1]

文档总结

1. 本题的贪心改进和动态规划法都非常炸裂!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值