代码随想录算法训练营-贪心算法-2|55. 跳跃游戏、45. 跳跃游戏 II、1005. K 次取反后最大化的数组和
55. 跳跃游戏
1. 跳跃的覆盖范围。这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点!
2. 贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。
- 时间复杂度: O(n)
- 空间复杂度: O(1)
1 class Solution: 2 def canJump(self, nums: List[int]) -> bool: 3 cover = 0 4 if len(nums) == 1: return True 5 i = 0 6 # python不支持动态修改for循环中变量,使用while循环代替 7 while i <= cover: 8 cover = max(i + nums[i], cover) 9 if cover >= len(nums) - 1: return True 10 i += 1 11 return False
1. 目标是使用最少的跳跃次数到达数组的最后一个位置。
2. 说明: 假设你总是可以到达数组的最后一个位置。
3. 这里需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖。
- 如果当前覆盖最远距离下标不是是集合终点,步数就加一,还需要继续走。
- 如果当前覆盖最远距离下标就是是集合终点,步数不用加一,因为不能再往后走了。
- 时间复杂度: O(n)
- 空间复杂度: O(1)
1 class Solution: 2 def jump(self, nums): 3 if len(nums) == 1: 4 return 0 5 6 cur_distance = 0 # 当前覆盖最远距离下标 7 ans = 0 # 记录走的最大步数 8 next_distance = 0 # 下一步覆盖最远距离下标 9 10 for i in range(len(nums)): 11 next_distance = max(nums[i] + i, next_distance) # 更新下一步覆盖最远距离下标 12 if i == cur_distance: # 遇到当前覆盖最远距离下标 13 ans += 1 # 需要走下一步 14 cur_distance = next_distance # 更新当前覆盖最远距离下标(相当于加油了) 15 if next_distance >= len(nums) - 1: # 当前覆盖最远距离达到数组末尾,不用再做ans++操作,直接结束 16 break 17 18 return ans
1. 局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
2. 那么本题的解题步骤为:
- 第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
- 第二步:从前向后遍历,遇到负数将其变为正数,同时K--
- 第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
- 第四步:求和
- 时间复杂度: O(nlogn)
- 空间复杂度: O(1)
1 class Solution: 2 def largestSumAfterKNegations(self, A: List[int], K: int) -> int: 3 A.sort(key=lambda x: abs(x), reverse=True) # 第一步:按照绝对值降序排序数组A 4 5 for i in range(len(A)): # 第二步:执行K次取反操作 6 if A[i] < 0 and K > 0: 7 A[i] *= -1 8 K -= 1 9 10 if K % 2 == 1: # 第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完 11 A[-1] *= -1 12 13 result = sum(A) # 第四步:计算数组A的元素和 14 return result