LeetCode(45): 跳跃游戏 II
Hard!
题目描述:
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是2。
从下标为 0 跳到下标为 1 的位置,跳1步,然后跳3步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。
解题思路:
这题是之前那道Jump Game 跳跃游戏 的延伸,那题是问能不能到达最后一个数字,而此题只让我们求到达最后一个位置的最少跳跃数,貌似是默认一定能到达最后位置的? 此题的核心方法是利用贪婪算法Greedy的思想来解,想想为什么呢? 为了较快的跳到末尾,我们想知道每一步能跳的范围,这里贪婪并不是要在能跳的范围中选跳力最远的那个位置,因为这样选下来不一定是最优解,这么一说感觉又有点不像贪婪算法了。我们这里贪的是一个能到达的最远范围,我们遍历当前跳跃能到的所有位置,然后根据该位置上的跳力来预测下一步能跳到的最远距离,贪出一个最远的范围,一旦当这个范围到达末尾时,当前所用的步数一定是最小步数。
我们需要两个变量cur和pre分别来保存当前的能到达的最远位置和之前能到达的最远位置,只要cur未达到最后一个位置则循环继续,pre先赋值为cur的值,表示上一次循环后能到达的最远位置,如果当前位置i小于等于pre,说明还是在上一跳能到达的范围内,我们根据当前位置加跳力来更新cur,更新cur的方法是比较当前的cur和i + A[i]之中的较大值,如果题目中未说明是否能到达末尾,我们还可以判断此时pre和cur是否相等,如果相等说明cur没有更新,即无法到达末尾位置,返回-1。
C++解法一:
class Solution {
public:
int jump(vector<int>& nums) {
int res = , n = nums.size(), i = , cur = ;
while (cur < n - ) {
++res;
int pre = cur;
for (; i <= pre; ++i) {
cur = max(cur, i + nums[i]);
}
if (pre == cur) return -; // May not need this
}
return res;
}
};
还有一种写法,跟上面那解法略有不同,但是本质的思想还是一样的,关于此解法的详细分析可参见http://www.cnblogs.com/lichen782/p/leetcode_Jump_Game_II.html。这里cur是当前能到达的最远位置,last是上一步能到达的最远位置,我们遍历数组,首先用i + nums[i]更新cur,这个在上面解法中讲过了,然后判断如果当前位置到达了last,即上一步能到达的最远位置,说明需要再跳一次了,我们将last赋值为cur,并且步数res自增1,这里我们小优化一下,判断如果cur到达末尾了,直接break掉即可。
C++解法二:
class Solution {
public:
int jump(vector<int>& nums) {
int res = , n = nums.size(), last = , cur = ;
for (int i = ; i < n - ; ++i) {
cur = max(cur, i + nums[i]);
if (i == last) {
last = cur;
++res;
if (cur >= n - ) break;
}
}
return res;
}
};
要理解这个算法,首先明白,这个题只要我们求跳数,怎么跳,最后距离是多少,都没让求的。
大牛这个算法的思想主要是,扫描数组(废话。。。),以确定当前最远能覆盖的节点,放入curr。然后继续扫描,直到当前的路程超过了上一次算出的覆盖范围,那么更新覆盖范围,同时更新条数,因为我们是经过了多一跳才能继续前进的。
形象地说,这个是在争取每跳最远的greedy。举个栗子。
比如就是我们题目中的[2,3,1,1,4]。初始状态是这样的:cur表示最远能覆盖到的地方,用红色表示。last表示已经覆盖的地方,用箭头表示。它们都指在第一个元素上。

接下来,第一元素告诉cur,最远咱可以走2步。于是:

下一循环中,i指向1(图中的元素3),发现,哦,i小于last能到的范围,于是更新last(相当于说,进入了新的势力范围),步数ret加1.同时要更新cur。因为最远距离发现了。

接下来,i继续前进,发现i在当前的势力范围内,无需更新last和步数ret。更新cur。

i继续前进,接下来发现超过当前势力范围,更新last和步数。cur已然最大了。

最后,i到最后一个元素。依然在势力范围内,遍历完成,返回ret。

这道题让我们明白一个道理:
不要做无必要的计算。
对了,有同学会问,那为啥要用last,直接用curr跳不就行了。直接用curr跳那每次都是跳最远的,但是最优路径不不一定是这样。该算法时间复杂度为O(n)。
C++解法三:
/*
* We use "last" to keep track of the maximum distance that has been reached
* by using the minimum steps "ret", whereas "curr" is the maximum distance
* that can be reached by using "ret+1" steps. Thus,
* curr = max(i+A[i]) where 0 <= i <= last.
*/
class Solution {
public:
int jump(int A[], int n) {
int ret = ;
int last = ;
int curr = ;
for (int i = ; i < n; ++i) {
if (i > last) {
last = curr;
++ret;
}
curr = max(curr, i+A[i]);
} return ret;
}
};
LeetCode(45): 跳跃游戏 II的更多相关文章
- LeetCode 45. 跳跃游戏 II | Python
45. 跳跃游戏 II 题目来源:https://leetcode-cn.com/problems/jump-game-ii 题目 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素 ...
- Java实现 LeetCode 45 跳跃游戏 II(二)
45. 跳跃游戏 II 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [ ...
- [leetcode] 45. 跳跃游戏 II(Java)(动态规划)
45. 跳跃游戏 II 动态规划 此题可以倒着想. 看示例: [2,3,1,1,4] 我们从后往前推,对于第4个数1,跳一次 对于第3个数1,显然只能跳到第4个数上,那么从第3个数开始跳到最后需要两次 ...
- 力扣Leetcode 45. 跳跃游戏 II - 贪心思想
这题是 55.跳跃游戏的升级版 力扣Leetcode 55. 跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃 ...
- leetcode 45. 跳跃游戏 II JAVA
题目: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [2,3,1,1, ...
- [LeetCode] 45. 跳跃游戏 II
题目链接 : https://leetcode-cn.com/problems/jump-game-ii/ 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位 ...
- leetcode 55. 跳跃游戏 及 45. 跳跃游戏 II
55. 跳跃游戏 问题描述 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1, ...
- LeetCode 45跳跃游戏&46全排列
原创公众号:bigsai,回复进群加入力扣打卡群. 昨日打卡:LeetCode 42字符串相乘&43通配符匹配 跳跃游戏 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中 ...
- 【LeetCode】跳跃游戏II
[问题]给定一个非负整数数组,你最初位于数组的第一个位置.数组中的每个元素代表你在该位置可以跳跃的最大长度.你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [,,,,] 输出: ...
- 45. 跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [2,3,1,1,4]输出 ...
随机推荐
- ubuntu14安装node0.12.7
1. 官网下载linux系统二进制文件, 链接如下: https://nodejs.org/ 2. 解压到/opt/目录 3. 设置node环境变量 export NODE_HOME=/opt/nod ...
- raise TemplateDoesNotExist
raise TemplateDoesNotExist(template_name, chain=chain)django.template.exceptions.TemplateDoesNotExis ...
- 私有仓库GitLab快速入门篇
私有仓库GitLab快速入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 安装文档请参考官网:https://about.gitlab.com/installation/#ce ...
- Golang面向过程编程-函数
Golang面向过程编程-函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是函数 简单的说函数的作用就是把程序里多次调用的相同的代码部分定义成一份,然后起个名字,所有的 ...
- logstash 常用参数
最近在折腾logstash,其处理流程不过于input.filter.output三个处理流程,以下是我翻译的几个常用的处理参数 output流之http output { http { codec ...
- 学习windows编程 day4 之 多边矩形填充
#include <windows.h> #include <math.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, ...
- javascript Date定义和体验
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- UESTC - 1324 卿学姐与公主
题目链接 某日,百无聊赖的卿学姐打开了某11区的某魔幻游戏 在这个魔幻的游戏里,生活着一个美丽的公主,但现在公主被关押在了魔王的城堡中. 英勇的卿学姐拔出利刃冲向了拯救公主的道路. 走过了荒野,翻越了 ...
- Ant基础知识1
1.Ant简介 Apache Ant是一个将软件编译/测试/部署等步骤联系在一起加以优化的一个构建工具,常用于java环境中的软件开发.Ant的默认配置文件是build.xml. 对java语言的支持 ...
- 08-DML(插入、更新、删除)
1. 插入 (1). 插入完整数据记录 (2). 插入数据记录的一部分 (3). 插入多条记录(MySQL特有的) INSERT INTO table_name (column1,column2,co ...