Jump Game -- LeetCode

动态规划解决跳台阶问题
本文探讨使用动态规划方法解决跳台阶问题的经典实例,详细解释了局部最优与全局最优的概念,通过实例展示了如何通过一次遍历实现算法优化,达到O(n)时间复杂度和O(1)空间复杂度的目标。
原题链接: http://oj.leetcode.com/problems/jump-game/
这道题是动态规划的题目,所用到的方法跟是在 Maximum Subarray 中介绍的套路,用“局部最优和全局最优解法”。我们维护一个到目前为止能跳到的最远距离,以及从当前一步出发能跳到的最远距离。局部最优local=A[i]+i,而全局最优则是global=Math.max(global, local)。递推式出来了,代码就比较容易实现了。因为只需要一次遍历时间复杂度是O(n),而空间上是O(1)。代码如下:
public boolean canJump(int[] A) {
    if(A==null || A.length==0)
        return false;
    int reach = 0;
    for(int i=0;i<=reach&&i<A.length;i++)
    {
        reach = Math.max(A[i]+i,reach);
    }
    if(reach<A.length-1)
        return false;
    return true;
}
这也是一道比较经典的动态规划的题目,不过不同的切入点可能会得到不同复杂度的算法,比如如果维护的历史信息是某一步是否能够到达,那么每一次需要维护当前变量的时候就需要遍历前面的所有元素,那么总的时间复杂度就会是O(n^2)。所以同样是动态规划,有时候也会有不同的角度,不同效率的解法。这道题目还有一个扩展 Jump Game II ,有兴趣的朋友可以看看。
你提供的代码是 **LeetCode 第55题:跳跃游戏(Jump Game)** 的标准贪心算法解法。该算法通过维护一个变量 `rightmost` 来记录当前能够到达的最远位置,从而判断是否可以跳到最后一个下标。 --- ## ✅ 代码解析完整 VS2022 可运行版本 以下是适合在 **Visual Studio 2022 (VS2022)** 中运行的完整代码版本,包含 `vector`、主函数和测试用例。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; class Solution { public: bool canJump(vector<int>& nums) { int n = nums.size(); int rightmost = 0; for (int i = 0; i < n; ++i) { if (i <= rightmost) { // 如果当前位置i是可以到达的 rightmost = max(rightmost, i + nums[i]); // 更新最远可达位置 if (rightmost >= n - 1) { return true; // 已能到达或超过终点 } } } return false; // 循环结束仍未到达终点 } }; // 主函数测试 int main() { Solution sol; vector<int> nums; // 测试用例 1 nums = {2, 3, 1, 1, 4}; cout << "输入数组: "; for (int num : nums) cout << num << " "; cout << "\n能否跳到最后?" << (sol.canJump(nums) ? "true" : "false") << endl << endl; // 测试用例 2 nums = {3, 2, 1, 0, 4}; cout << "输入数组: "; for (int num : nums) cout << num << " "; cout << "\n能否跳到最后?" << (sol.canJump(nums) ? "true" : "false") << endl << endl; // 测试用例 3 nums = {0}; cout << "输入数组: "; for (int num : nums) cout << num << " "; cout << "\n能否跳到最后?" << (sol.canJump(nums) ? "true" : "false") << endl << endl; // 测试用例 4 nums = {1, 0, 2}; cout << "输入数组: "; for (int num : nums) cout << num << " "; cout << "\n能否跳到最后?" << (sol.canJump(nums) ? "true" : "false") << endl << endl; return 0; } ``` --- ## ✅ 示例输出 ``` 输入数组: 2 3 1 1 4 能否跳到最后?true 输入数组: 3 2 1 0 4 能否跳到最后?false 输入数组: 0 能否跳到最后?true 输入数组: 1 0 2 能否跳到最后?false ``` --- ## ✅ 算法逻辑详解 ### ✅ 问题背景 给定一个非负整数数组 `nums`,你最初位于数组的第一个下标。每个下标 `i` 对应一个非负整数 `nums[i]`,表示你可以跳跃的最大步数。你的任务是判断是否可以从第一个下标跳到最后一个下标。 ### ✅ 解法思路:贪心算法(Greedy) #### 核心思想: - 维护一个变量 `rightmost`,表示当前能够到达的最远下标。 - 遍历数组: - 如果当前位置 `i` 在 `rightmost` 范围内,说明可以到达; - 更新 `rightmost` 为 `max(rightmost, i + nums[i])`; - 如果 `rightmost >= n - 1`,说明可以到达终点,直接返回 `true`; - 如果遍历结束后仍未到达终点,返回 `false`。 --- ## ✅ 时间空间复杂度 | 类型 | 复杂度 | 说明 | |------|--------|------| | 时间复杂度 | O(n) | 只遍历一次数组 | | 空间复杂度 | O(1) | 只使用常数级额外空间 | --- ## ✅ 常见问题排查(VS2022) 1. **编译错误** - 确保包含 `<vector>` 和 `<algorithm>` - 使用 `using namespace std;` 或加上 `std::` 前缀 2. **运行时错误** - 注意空数组处理(题目保证数组长度 ≥ 1) - 确保访问 `nums[i]` 不越界 3. **逻辑错误** - 初始 `rightmost` 为 0 是关键 - `if (i <= rightmost)` 是防止不可达点的判断条件 --- ## ✅ 对比其他解法 | 解法 | 时间复杂度 | 空间复杂度 | 特点 | |------|------------|------------|------| | 贪心算法(当前方法) | O(n) | O(1) | 最优解,推荐 | | 动态规划(从后往前) | O(n²) | O(n) | 思路清晰但效率低 | | BFS / DFS | O(n²) | O(n) | 可以解决问题,但不推荐 | | 递归+记忆化搜索 | O(n²) | O(n) | 适合拓展思路 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值