返回

算法日记| LeetCode 第 45 题跳跃游戏 II 的解题思路和技巧

后端

如何跳跃到胜利:掌握跳跃游戏 II

简介

在 LeetCode 第 45 题跳跃游戏 II 中,我们面临一个有趣的挑战:如何在给定的数组中以最少的跳跃次数到达终点。这可不是一个简单的任务,但使用适当的算法,我们可以优雅地解决它。

贪心算法:一步一步接近胜利

贪心算法是一种直观的解决方法。它通过在每一步做出最优选择来逐步逼近最佳解。在跳跃游戏中,我们的贪心策略很简单:从起点出发,寻找能跳到最远位置的步数,然后将该位置设为我们的下一步。我们不断重复这一过程,直到到达终点。

代码实现(贪心算法):

def jump_greedy(nums):
    jumps, end, farthest = 0, 0, 0
    for i in range(len(nums) - 1):  # 遍历数组(最后一个位置除外)
        farthest = max(farthest, nums[i] + i)  # 更新最远可达位置
        if i == end:  # 如果到达当前跳跃的终点
            jumps += 1  # 增加跳跃次数
            end = farthest  # 更新跳跃终点
            if end >= len(nums) - 1:  # 如果达到终点
                break  # 结束循环
    return jumps

动态规划:从过去中学习

动态规划算法以另一种方式解决问题:它将问题分解成子问题,并逐个解决它们。在跳跃游戏中,我们的子问题是:从数组中的特定位置跳到终点的最少跳跃次数。

代码实现(动态规划):

def jump_dp(nums):
    n = len(nums)
    dp = [float('inf')] * n  # 初始化动态规划表
    dp[0] = 0  # 起点跳跃次数为 0
    for i in range(1, n):  # 遍历数组
        for j in range(i):  # 遍历之前的位置
            if nums[j] + j >= i:  # 如果可以从位置 j 跳到位置 i
                dp[i] = min(dp[i], dp[j] + 1)  # 更新位置 i 的最小跳跃次数
    return dp[-1]  # 返回终点的最小跳跃次数

比较贪心算法和动态规划

这两种算法各有优势。贪心算法简单易懂,但在某些情况下可能不是最优的。动态规划可以找到最优解,但计算成本更高。对于较小的数组,贪心算法通常就足够了,而对于较大的数组,动态规划更可靠。

实战:代码示例

考虑以下示例数组:[2, 3, 1, 1, 4]

贪心算法:

  • 从起点跳到位置 1 (2 步)
  • 从位置 1 跳到位置 4 (1 步)

总跳跃次数:2

动态规划:

  • 从起点跳到位置 1 (1 步)
  • 从位置 1 跳到位置 4 (1 步)

总跳跃次数:2

常见问题解答

  1. 贪心算法为什么有时不是最优的?

    • 贪心算法只考虑当前步的最优选择,而不考虑全局的影响。在某些情况下,这可能导致次优解。
  2. 动态规划的计算复杂度是多少?

    • 动态规划的时间复杂度为 O(n^2),其中 n 是数组的长度。
  3. 如何处理无法到达终点的数组?

    • 我们可以返回 -1 来表示无法到达终点。
  4. 还有其他解决此问题的算法吗?

    • 除了贪心算法和动态规划,还有其他算法,如广度优先搜索 (BFS) 和深度优先搜索 (DFS)。
  5. 跳跃游戏 II 在实际应用中有哪些?

    • 跳跃游戏 II 算法在许多领域都有应用,如路径规划和资源优化。