LeetCode_跳跃游戏
本文通过跳跃游戏的几个算法例题总结一下相关贪心算法,开始学习的阶段,借鉴好的算法思路并学习,也巩固一下最近学习的算法。(后续遇到贪心算法会续更~~)
前言
贪心算法——在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性(即某个状态以后的过程不会影响以前的状态,只与当前状态有关。)
贪心算法的基本思路:
- 建立数学模型来描述问题
- 把求解的问题分成若干个子问题
- 对每个子问题求解,得到子问题的局部最优解
- 把子问题的解局部最优解合成原来问题的一个解
该算法存在的问题:
- 不能保证求得的最后解是最佳的
- 不能用来求最大值或最小值的问题
- 只能求满足某些约束条件的可行解的范围
贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
一、跳跃游戏I
=>题目: 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1: 输入:nums = [2,3,1,1,4] 输出:true 解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。 示例 2: 输入:nums = [3,2,1,0,4]输出:false 解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示: 1 <= nums.length <= 3 * 104 0 <= nums[i] <= 105
大致思路: 分析: 由题目得出,要想到达最后一个下标,得满足两个条件:
1、假设每个位置都能跳到,那么只需要遍历数组,看看有没有位置能直接通过这个位置上的数字跳到结尾。 比如[2,3,1,1,4],我们遍历数字,看看哪个位置可以跳到最后,可以发现第三个位置的数字是2,所以可以通过第三个位置跳到最后的下标,数组成立。
2、上述假设成立的还有个条件就是每个位置是否都能跳到。 比如[3,2,1,0,4],按照上面的逻辑,第三个位置可以跳跃1步到第4个位置,但第4个位置不可跳跃,因此不能到达最后位置。
public class CanJumpGames {
public boolean canJump(int[] nums) {
int step = 1;
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] >= step) {
step = 1;
} else {
step++;
}
if (i == 0 && step > 1) {
return false;
}
}
return true;
}
public boolean canJump(int[] nums) {
int k =0;
int len = nums.length;
for(int i=0;i<len ;i++){
if(k<i) return false;
k=Math.max(k,i+nums[i]);
if (k >= len -1) {
return true;
}
}
return false;
}
}
二、跳跃游戏II
题目: 给你一个非负整数数组 nums ,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 假设你总是可以到达数组的最后一个位置。 示例 1: 输入: nums = [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 示例 2: 输入: nums = [2,3,0,1,4] 输出: 2
大致思路: 简单分析:[2,3,1,1,4]中,第一步数字是2,可以跳到数字是3和数字是1的两个地方,贪心选择大的,即选择跳到3那步;从3即下标1的位置可以跳到数字分别是1,1,4的三个地方,贪心选择4;而4即为最后一位,最终结果是需要跳2次。
public class CanJump2 {
public int jump(int[] nums) {
if(nums.length == 1) {return 0;}
int reach = 0;
int nextreach = nums[0];
int step = 0;
for(int i = 0;i<nums.length;i++){
nextreach = Math.max(i+nums[i],nextreach);
if(nextreach >= nums.length-1) {return (step+1);}
if(i == reach){
step++;
reach = nextreach;
}
}
return step;
}
public int jump01(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = 0;
for (int i = 1; i < nums.length; i++) {
dp[i] = Integer.MAX_VALUE;
for (int j = 0; j < i; j++) {
if (i - j <= nums[j]) {
dp[i] = Math.min(dp[i], dp[j] + 1);
}
}
}
return dp[nums.length - 1];
}
}
|