[Week 7] LeetCode 45 & 55. Jump Game I & II

15 篇文章 0 订阅
13 篇文章 0 订阅

LeetCode 45 & 55. Jump Game I & II

Jump Game I

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.

Example 1

Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Example 2

Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum
             jump length is 0, which makes it impossible to reach the last index.

题解

这个问题我们可以理解成这样:我们从index=0开始,扫描整个数组,每次更新当前所能覆盖的最远距离,最后判断是否覆盖了终点即可。

例1:(我们用O表示当前数组中能跳跃到的位置)

  1. index=0: [O,O,O,X,X]
  2. index=1: [O,O,O,O,O]

例2:(我们最多只能覆盖到[0,3]

  1. index=0: [O,O,O,O,X]
  2. index=1: [O,O,O,O,X]
  3. index=2: [O,O,O,O,X]
  4. index=3: [O,O,O,O,X]

看起来很简单对吧,我们可以把这样的算法叫贪心算法(采取步步逼近的方式构造问题的解,其下一步的选择总是在当前看来收效最快和效果最明显的哪一个)

因为这个题相对比较简单就直接上代码了。

Code

class Solution {
public:
    bool canJump(vector<int>& nums) {
        // rightMost is the farthest index we can reach
        int rightMost = 0;
        for (int i = 0; i < nums.size() - 1 && rightMost < nums.size(); ++i) {
            if (rightMost < i) break;
            rightMost = max(rightMost, i + nums[i]);
        }
        return rightMost >= nums.size() - 1;
    }
};

复杂度分析

代码和想法都是如此简单,只扫描一次数组,即时间复杂度为O(n)

Jump Game II

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.

Your goal is to reach the last index in the minimum number of jumps.

Example

Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
    Jump 1 step from index 0 to 1, then 3 steps to the last index.

Note:

You can assume that you can always reach the last index.

题解

相比Jump Game I,这个题假设了能够到达,但要我们计算最少几次跳能到达终点。

又是这种类似最短路径的问题,我们可以用BFS来暴力搜解,但对于这种只求步数问题,用BFS是需要消耗大量空间的,事实证明这题是卡了空间的,暴力只会送你Memory Limit Exceeded

那我们来想想能不能用上一题的思路来求解,想象一下自己站在一个区间内:[begin, reached],在这个区间内你能到达的最远距离为nextReached,意思就是你下一条的区间为:[reached + 1, nextReached],然后再执行上述操作,直到你的所在区间包含终点为止。我们的算法可以概括为一下步骤:

  1. 扫描当前所在区间:[begin, reached],找到在这个区间内能跳到的最远距离nextReached
  2. 扫描完后,将区间替换为[reached + 1, nextReached],再执行步骤1直到区间包含终点为止

为什么正确?

每个区间代表着你上一跳能达到的所有位置,拿上面的示例来说:

  1. 第一个区间:[0,0],下一跳区间:[1,2]
  2. 第二个区间:[1,2],下一跳区间:[3,4](达到终点)

这其实也是一种贪心的策略,每次都将数组划分成更小的数组,且每次决策都是对当前来说最好的,例如上面的示例中,如果你跳的路径为:0->2->...而不是0->1->4,那么跳的次数一定会更多。

Code

class Solution {
public:
    int jump(vector<int> &nums)
    {
      int times = 0, reached = 0, nextReached = 0;
      for (int i = 0; i < nums.size() - 1; ++i)
      {
        if (i > reached)
          return -1;
        if (reached >= nums.size() - 1)
          return times;
        nextReached = max(nextReached, i + nums[i]);
        if (i == reached)
        {
          times++;
          reached = nextReached;
        }
      }
      return times;
    }
};

复杂度分析

同上题一样,我们做的工作只有扫描整个数组,只不过多维护了两个变量罢了,所以时间复杂度依然为O(n)。而且比起BFS,其空间复杂度也是要好得多,只是维护了两个变量而已。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值