数组跳跃游戏 Jump Game

本文针对LeetCode中的跳跃游戏问题提出三种解法:直接遍历、贪心算法与动态规划。通过对每种方法的深入探讨,帮助读者理解算法背后的逻辑与应用技巧。

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

题目源自于leetcode。

题目:Given an array of non-negative integers, you are initially positioned at the first index of the array.Each element in the array represents your maximum jump length at that position.Determine if you are able to reach the last index.
For example:

A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.

思路一:依靠题目的规则循规蹈矩。

    解题的一个重要思想是想到各种极端情况,考虑周全。

    数组中的数都是非负整数,所以如果数组内没有0的话,一定是从开始能跳到最后的。如果有0的话,必须有办法跳到0的右边去。

极端的一个情况是这样的,543210...那么怎么也跳不到0右面。所以至少需要0的左边有个数的大于它到0的距离。

刚才只考虑了单独1个0,对于连续的多个0,就需要其左边的某个数大于到最右的0的距离。

另外,不管最后一个数是什么,只要到达它即可,所以我的首个研究对象应该是倒数第二个数。

    

解决步骤:根据这个思路,我对数组从右向左遍历。当遇到0或0s时,就开始判断其左边是否存在值大于到最右0的距离的数。当再次遇到0或0s时,若没有找到这样的数,则宣布失败(无法完成跳跃);若有这样的数,重新开始下一轮判断。该方法时间复杂度为O(N)。

注意每个while遍历的都应该做超出边界值的检查。

class Solution {
public:
    bool canJump(int A[], int n) {
	if(A == NULL || n <= 0)
		return false;
  	int i = n-2;
	int idx_0;
	int flag;

  	while(i >= 0)
	{
		if(A[i] == 0)
		{
			flag = 0;
			idx_0 = i;
			i--;
			while(i >=0 && A[i] == 0)
				i--;
			while(i >=0 && A[i] != 0)
			{
				if(A[i] > idx_0 - i)
					flag = 1;
				i--;
			}
			if(flag == 0)
				return false;
			else
				continue;
		}
		i--;
	}
	return true;
    }
};

思路二:贪心法。记录一个变量保持最远可达的位置。从左到右遍历时,不断刷新这个最远距离。

class Solution {
public:
    bool canJump(int A[], int n) {
        int reach = 1;
        for(int i=0;i<reach && reach < n;i++)
            reach = max(reach, i + 1 + A[i]);
        return reach >= n;
    }
};
思路三:动态规划法。不过在此就没必要了,空间复杂度太高。
class Solution {
public:
    bool canJump(int A[], int n) {
        vector<int> v(n, 0);
        for(int i=1;i<n;i++)
        {
            v[i] = max(v[i-1], A[i-1]) - 1; //状态递推
            if(v[i] < 0) 
                return false;
        }
        return v[n-1] >= 0;
    }
};

"跳跃游戏"通常指的是一个经典的问题,涉及到在一个二维数组(如网格)中寻找最短路径,玩家可以从一个格子跳到与其水平或垂直方向距离相等的其他格子。这个题目可以用动态规划来解决,具体实现函数 `jumpGame` 可以分为以下几个步骤: 1. 定义一个二维布尔数组 `dp`,其中 `dp[i]` 表示从起始位置 `i` 是否可以达到终点。初始时,除了起点 `dp[0]=true` 其他都设为 `false`。 2. 对于每一个位置 `i`,有两个可能的操作: a. 向右跳到 `i + 1`,前提是当前位置和下个位置在同一行,并且 `dp[i + 1]` 未被设置过,这时我们设置 `dp[i] = true`,表示可以通过一次跳跃到达。 b. 向下跳到 `j = i + arr[i][0]`,这是由于我们可以在当前列的最大跳远范围内向上跳,找到最远的可到达位置。如果 `j` 小于数组长度并且 `dp[j]` 未被设置,那说明可以通过跳跃到达,此时设置 `dp[i] = dp[j]` 并记录路径。 3. 从当前位置 `i` 开始,查找所有可能的可到达位置,并不断更新 `dp` 数组。直到找到最后一个位置 `n-1`,如果 `dp[n-1]` 为真,则说明可以跳到最后一个位置,返回 `1`(因为至少需要一次跳跃)。如果所有位置都被检查过,但找不到可到达终点的位置,则返回 `-1` 表示无法到达。 Python 代码示例: ```python def jumpGame(nums): n = len(nums) dp = [False] * n dp[0], steps = True, 0 farthest_reach = [0] * n for i in range(n): if dp[i]: farthest_reach[i] = i + nums[i] for step in range(1, n): for i in range(step, n): if i >= farthest_reach[step - 1]: break if dp[i] or i + nums[i] > farthest_reach[step - 1]: dp[i] = True farthest_reach[step] = max(farthest_reach[step], i + nums[i]) return int(dp[-1]) if dp[-1] else -1 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值