[LeetCode 45] Jump Game II

题意

    给一个数组A, A[i] 表示在 i 这个位置最多能移动多远,i.e.在位置 i 最多移动到 A[i] + i 这个位置。问从数组第一个元素开始,最少移动多少次,能够到达数组的最后一个元素?我们假设始终能够到达数组的最后一个元素。


思路

    最直接的想法是在位置 i 处,更新 [ i + 1, i + A[i] ] 范围内的最少移动次数。但如果数组A中的元素都很大,这种方法的效率很低,是O(n^2),结果是TLE。

    注意到,如果能够在 s 次移动之后到达位置 k, 则任意位置 i,只要 i < k,都可以在最多 s 次移动之后到达。不严谨的证明如下:存在位置 j,满足 j < k,且经过 s-1 次移动能够到达 j(因为我们假设能够用 s 次移动到达 k)。这样在范围 [ j+1, k ] 的位置都可以在 s 次移动之后到达。对那些在 j 之前的位置,用相同的方法可以得知一定能在 s-1 的步数内到达。因此,所有在 k 之前的位置,都能够用最多 s 步到达。

    如果已经知道了能在 s 步以内到达 [ 0, k ] 范围内的位置 ( k >= 0),就可以知道在 s+1 步以内能够到达的位置。开一个数组保存当前能到达的最远位置,这可以在O(n)时间内完成。之后模拟着走一遍就行了,总的时间复杂度是 O(n)。


C++代码

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

class Solution
{
public:
    int jump(vector<int> &vec)
    {
        vector<int> far(vec.size()+10, 0);
        far[0]=vec[0];
        for(int i=1;i<vec.size();i++)
            far[i]=max(far[i-1],i+vec[i]);
        int ans=0,pos=0;
        while(pos<vec.size()-1)
        {
            ans++;
            pos=far[pos];
        }

        return ans;
    }
};

python代码

class Solution:
    def jump(self, nums):
        far = [nums[0]]
        for i in range(1, len(nums)):
            far.append(max(far[i-1], i+nums[i]))
        pos = 0
        ans = 0
        size = len(nums)
        while pos < size - 1:
            ans += 1
            pos = far[pos]
        
        return ans

猜你喜欢

转载自blog.csdn.net/perfectcherryblossom/article/details/80084802