LeetCode045——跳跃游戏II

本文深入解析了LeetCode上“跳过障碍:游戏II”问题的多种解决方案,包括回溯法、动态规划及贪心算法。重点阐述了贪心算法的原理与实现,解释了为何在此类问题中贪心算法更为高效。通过对比不同算法的时间与空间复杂度,揭示了贪心算法在解决此类问题上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:https://leetcode-cn.com/problems/jump-game-ii/description/

题目描述:

知识点:贪心算法

思路一:回溯法(在LeetCode中提交会超时)

回溯法的思想很简单,寻找到所有能到达数组的最后一个位置的可能路径,计算其最短值即可。由于是穷举,其时间复杂度是很高的,达到了O(nums[0] + nums[1] + nums[2] + ... + nums[n - 1])级别,其中n为nums数组的长度。而空间复杂度则是递归深度,是O(n)级别的。

JAVA代码:

//backtracking
public class Solution {
	
	int steps;
 
	public int jump(int[] nums) {
        int n = nums.length;
        steps = n - 1;
        
        jump(nums, 0, 0);
        
        return steps;
    }
	
	/*
	 * Now I'm in the indexth position of nums, I have take tempSteps steps
	 */
	private void jump(int[] nums, int index, int tempSteps) {
		if(index >= nums.length - 1) {
			if(index == nums.length - 1) {
				steps = Math.min(steps, tempSteps);
			}
			return;
		}
		for (int i = 1; i <= nums[index]; i++) {
			jump(nums, index + i, tempSteps + 1);
		}
	}
}

思路二:动态规划(在LeetCode中提交会超时)

状态定义:f(x, y)--------表示从索引x,走到索引y的最短步数

状态转移

(1)如果nums[x] + x >= y,说明一步就可以从索引x走到索引y,f(x, y) = 1。

(2)如果nums[x] + x < y,f(x, y) = 1 + min{f(x + 1,y), f(x + 2, y), ... , f(x + nums[x], y)}。

时间复杂度和空间复杂度都是O(n ^ 2)级别的。

JAVA代码:

public class Solution {
 
	//dynamic programming
	public int jump(int[] nums) {
        int n = nums.length;
        if(n == 1) {
        	return 0;
        }
        int[][] steps = new int[n][n];
        for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				steps[i][j] = n - 1;
			}
		}
        for (int i = 0; i < n; i++) {
			steps[i][i] = 0;
		}
        for (int i = 0; i >= 1 - n; i--) {
			for (int j = 0; j < n + i; j++) {
				if(nums[j] + j >= j - i) {
					steps[j][j - i] = 1;
				}else {
					for (int k = 1; k <= nums[j]; k++) {
						steps[j][j - i] = Math.min(steps[j][j - i], 1 + steps[j + k][j - i]);
					}
				}
			}
		}
        return steps[0][n - 1];
    }
}

思路三:贪心算法

既然动态规划都超时了,那么必然就得用贪心算法了。贪心算法的本质是在动态规划的基础上舍弃一些不可能的情况,类似于回溯算法的剪枝过程。

对于本题而言,假设我们现在在索引i的位置。

如果索引i的值为0,那么我们不可能再继续前进了,这种情况舍弃。

如果索引i的值不为0,那么我们下一步可以走到索引i + k(1 <= k <= nums[i])。而在索引i + k我们又可以走到索引i + k + p(1 <= p <= nums[i + k]),我们选取索引i + k的原则是i + k + p取得最大值。

对于贪心算法而言,其实现永远不是重点,其重点在于为什么可以使用贪心算法。那么,为什么本题可以这样使用贪心算法呢?

(1)如果此时i + k + p的最大值仍然小于数组的长度 - 1,说明经过此步还未能抵达数组中最后一个元素。

对于索引i而言,假设索引i下一步的最优解为索引i + k。索引i + k的下一步所能到达的范围是索引i + k + 1 ~ i + k + nums[i + k]。

假设索引i + k不是索引i下一步的最优解,索引i下一步的最优解为索引i + j(j != k)。索引i + j的下一步所能到达的范围是索引i + j + 1 ~ i + j + nums[i + j],由索引i + k的定义可知,i + j + nums[i + j] <= i + k + nums[i + k]。

如果j >= k,那么i + j + 1 >= i + k + 1,索引i + j的下一步所能到达的范围是小于索引i + k所能到达的范围的,即如果索引i + j能到的地方,索引i + k也能到,但是索引i + k能到的地方,索引i + j却不一定能到。因此索引i下一步的最优解一定只可能是i + k。

如果j < k,对于索引i + k + 1及其之后的索引位置,索引i + j的下一步所能到达的范围是小于索引i + k所能到达的范围的,即如果索引i + j能到的地方,索引i + k也能到,但是索引i + k能到的地方,索引i + j却不一定能到。对于索引i + k + 1之前的索引位置,索引i + k是到不了的,索引i + j能到,但是此时多走了一步路。因为我们最终肯定是要跨过索引i + k,我们本可以一步到达索引i + k的位置,下一步就跨过索引i + k了,现在我们第一步到达索引i + j的位置,下一步还不能保证跨过索引i + k。因此索引i下一步的最优解一定只可能是i + k。

(2)如果此时i + k + p的最大值大于等于数组的长度 - 1,说明经过此步能抵达数组中最后一个元素,显然索引i + k是最优解。

时间复杂度最差情况是O(n)级别的,其中n为nums数组的长度。在我的实现中,每次寻找i + k使得i + k + p最大的过程中都新建了一个数组,因此在我的实现中空间复杂度是O(n)级别的。

JAVA代码:

public class Solution {
	
	//greedy algorithm
	public int jump(int[] nums) {
        int n = nums.length;
        int steps = 0;
        int index = 0;
        while(index < n - 1) {
        	steps++;
        	int[] lengths = new int[nums[index]];
        	if(index + nums[index] >= n - 1) {
        		break;
        	}
        	for (int i = index + 1; i <= index + nums[index]; i++) {
				lengths[i - index - 1] = i + nums[i];
			}
        	int max = 0;
        	for (int i = 0; i < lengths.length; i++) {
				if(lengths[i] > lengths[max]) {
					max = i;
				}
			}
        	index = max + index + 1;
        }
        return steps;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值