代码随想录算法训练营第二十八天| 贪心2— 55. 跳跃游戏,45. 跳跃游戏 II,1005. K 次取反后最大化的数组和

贪心第二天,122. 买卖股票的最佳时机 II55. 跳跃游戏45. 跳跃游戏 II1005. K 次取反后最大化的数组和。依旧是感觉贪心像是智力题能想的出来就好写,想不出来真就是被绕进去。像是股票Ⅱ,一开始想的必须是必须低点买入直到高点才能卖出,忽略了这个过程中一直不停买卖也是一样的结果,能想清楚这个就会很容易。贪心真是一题一个样,每道题都能多少卡一会,然后看题解的时候就会恍然大悟,质疑自己这么简单的思路为啥刚才想不出来,然后下一道题接着卡,这就是做贪心题。

55. 跳跃游戏,45. 跳跃游戏 II

55. 跳跃游戏 - 力扣(LeetCode)

45. 跳跃游戏 II - 力扣(LeetCode)

两道思路类似的题目。Ⅰ是判断能否跳到最后一个数,Ⅱ是判断最短次数跳到最后一个数。一开始思考的思路是正确的,就是利用贪心,每一步都跳最远,然后去判断能否跳到最后/跳跃次数。但是做的时候发现个问题,就是类似2.7.1这种,如果在2跳到最远的1,实际上不如跳一步到7再跳。然后看题解学到了要用范围去理解这类题目,即不停使用i+nums[i]进行最大cover的维护。像在Ⅰ中,便是i不停向cover靠近,同时去不断更新这一段路程中,最远的点能跳到哪里,最后如果能cover到最后一个数就是True。举个反例[3,2,1,0,7]这里在i为0-2的时候,i+nums[i]都是3,所以只能cover到3,当i超过3之后,cover的值就不再更新了,也就是False。

Ⅱ是一样的cover思路,但是自己做的时候还是有错误。简单来说思路就是每次在当前跳跃范围内尽量向右扩展 next_distance,一旦走到当前层的边界,就执行一次跳跃并进入下一层,然后记录跳跃次数。就是类似于两层,一层是当前i正在循环的当前层,另外一层是最远层,每次i前进时,就记录这个最远层的最大值,当i在当前层走完时,当前层的最远点跳至最远层的最远点。也就是在一层遍历中,当前层中每个点的跳跃距离选最远的跳,最后记录跳多少次。

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

        return False


# 跳跃Ⅱ
class Solution:
    def jump(self, nums: List[int]) -> int:
        #每次在当前跳跃范围内尽量向右扩展 next_distance,一旦走到当前层的边界,就执行一次跳跃并进入下一层。
        cur_distance = 0  # 当前覆盖的最远距离下标
        ans = 0  
        next_distance = 0  # 下一步覆盖的最远距离下标
        
        for i in range(len(nums) - 1): #跳到最后一个位置就行,最后一个位置无需跳跃判断
            next_distance = max(nums[i] + i, next_distance)  # 更新下一步覆盖的最远距离下标
            if i == cur_distance:  # 遇到当前覆盖的最远距离下标
                cur_distance = next_distance  # 更新当前覆盖的最远距离下标
                ans += 1
        
        return ans

1005. K 次取反后最大化的数组和

1005. K 次取反后最大化的数组和 - 力扣(LeetCode)

暴力做法确实简单,直接排序k次数组执行k次最小数的转换就行,就是复杂度飞上天了。

然后想了想其他思路,感觉卡住的点是在于0,就是当所有负数都转化了,k仍然有次数,该怎么办这种情况。

学到一种新的排序方法,就是原数组利用绝对值大小进行排序,类似排序成[3,2,-1,0]这种。然后先进行一次遍历,将所有负数先转换了,而且这样排序肯定转变的是更小的负数,转变完就变成更大值了。然后就是解决我刚才思考不出来的点,就是还有次数但没负数的情况。这里的解法就是判断K剩余次数的奇偶数,如果为偶,那就相当于把一个最小正数反转再反转,就是没变,所以也不用额外操作。当剩余次数为奇,就把数组最后一个(之前倒序排,最后一个肯定最小)反转了,这样可以保证为最大值。

class Solution:
    def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
        # 暴力
        # for _ in range(k):
        #     nums.sort()
        #     nums[0] = -nums[0]

        # return sum(nums)

        nums.sort(key=lambda x: abs(x), reverse=True)

        for i in range(len(nums)):
            if nums[i] < 0 and k > 0:
                nums[i] *= -1
                k -= 1
            
        if k % 2 == 1:
            nums[-1] *= -1

        return sum(nums)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值