代码随想录第32天|122. 买卖股票的最佳时机 II、55. 跳跃游戏、45. 跳跃游戏 II

100 阅读2分钟

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

1. first idea

  1. 只要出现峰的拐点,就卖出.
  2. 只要出现谷的拐点,就买入。
  3. 如果最后一个是有股票扰卖出。
  4. 如果第一个点后是上坡就买入.

峰:

image.png

谷:

image.png

上坡起点:

image.png

2. doc

代码随想录 (programmercarl.com)

可以发现,其实我们需要收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润,不需要记录区间

那么只收集正利润就是贪心所贪的地方!

局部最优:收集每天的正利润,全局最优:求得最大利润

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        max_profit = 0
        for idx in range(1, len(prices)):
            if prices[idx] > prices[idx - 1]:
                max_profit += (prices[idx] - prices[idx - 1])
        return max_profit

55. 跳跃游戏

1. first idea

Question: 如果我能跳3步,我该跳几步才能让后面的位置正好能跳到终点?

2. doc

代码随想录 (programmercarl.com)

其实这个也没必要纠结。

而是只要看每个位置能覆盖的范围:

  1. 搞清楚当前位置的覆盖范围,
  2. 在这个范围内所有点的覆盖范围中找到最大的那个覆盖范围,
  3. 到这个最大范围对应的起点,然后执行1.2.
  4. 直到范围能够囊括最后一个位置即可。

自己实现了一下:

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        start_idx = 0
        range_length = nums[start_idx]
        while (start_idx + range_length) < (len(nums) - 1):
            max_dis = 0
            max_tmp_range = range_length
            for dis in range(1, range_length + 1):
                tmp_range = nums[start_idx + dis]
                if (start_idx + max_dis + max_tmp_range) <= (start_idx + dis + tmp_range):
                    max_tmp_range = tmp_range
                    max_dis = dis
            if max_dis == 0:
                # 没有找到更远的范围。
                # print(start_idx, max_dis, max_tmp_range, range_length)
                return False
            start_idx = start_idx + max_dis
            range_length = max_tmp_range
        return True

官方思路就是直接算一个从0开始的总得范围:

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        if len(nums) == 1:
            return True
        start_idx = 0
        range_length = nums[start_idx]
        idx = 0
        while idx < range_length + 1:  # 这里不能用for循环,因为for边界值不会在循环体更新。
            tmp_range = idx + nums[idx]
            if tmp_range > range_length:
                range_length = tmp_range
            idx += 1
            if range_length >= (len(nums) - 1):
                return True
        return False

45. 跳跃游戏 II

1. first idea

题目保证一定能跳到最后一个位置。

那我们每一步尽可能跳的最远,那就步数最少。

也就是在旧范围内能够为新范围贡献最大的那一步就是我们要选的。

那我们要如何找到这一步?

2. doc

代码随想录 (programmercarl.com)

实际上我们根本不需要找到是具体的哪一步贡献最大,而是只要还没覆盖到终点就加一步,因为没有这一步走不下去。

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        step_count = 0
        cur_range = 0
        next_range = 0
        for idx in range(len(nums)):
            next_range = max(idx + nums[idx], next_range)
            if idx == cur_range:  # 当前范围内能走到的最远的位置才开始更新范围,统计部署。
                step_count += 1  # 他一定是从起点到达这里的,所以步数要加一。
                cur_range = next_range  # 我们需要更新范围了
                if next_range >= len(nums) - 1:  
                    # 如果新的范围覆盖了终点就结束,否则就需要继续走下一步。
                    break
        return step_count