Jump Game II

来源:互联网 发布:2017金英杰免费网络课 编辑:程序博客网 时间:2024/04/30 16:57

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.

For example:
Given array A = [2,3,1,1,4]

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.)

看到题目之后,首先想到的应该是DP问题。那么重点是如何找到递推关系了,以S[i]表示到达i位置所需要的最少跳跃次数,最简单暴力的想法就是,从0-len对每个位置求解最少的跳跃次数,且有S[i + 1] = min{s[i - k] ...} + 1,其中i - k表示能够直接到达i + 1的位置,这样可以暴力的实现,然后一分析时间复杂度,这达到O(N^2)了,然后提交,发现不能过超时。

那么这肯定不是最高效的方法,可以换种思维来思考,现在在假设到达位置i,那么就可以计算出[i, i + nums[i]]这个区间的最小值,与之前的从i往前找能够到达的不一样,直接从i往后走,看它能够到达的范围内的值的最小值;这样一分析,复杂度就变成了O(sum(nums[i])), 如果每个nums[i]都足够大,那么时间复杂度还是不可以接受的。所以还要继续优化,怎么优化呢?再仔细分析,可以发现,其实对于[i, i + nums[i]]这个范围的最小值计算有时候是完全可以避免的,为什么呢?假设i - 1可以到达点i + 1, 也就是说,在i - 1的时候已经计算出其最小值为s[i - 1] + 1;当再计算i的时候,假设i + 1也在[i, i + nums[i]]的范围内,那这个时候,按照之前的做法,还要计算一遍s[i + 1],但是分析可以知道:s[i] + 1 >= s[i - 1] + 1,因为i - 1到达i最少的跳跃次数是0次,也就是说,无论怎么样i此时不可能修改s[i + 1]的值,所以这样的计算可以避免。为了实现这样的效果,设置一个curFar来表示当前已经计算的最远的点的位置,如果i + nums[i] <= curFar,那么我们可以不用计算i了;如果i + nums[i] > curFar,那就应该计算[curFar + 1, i + nums[i]]范围类的位置,只要发现len - 1在这个范围内,那么就可以结束计算了,已经找到了最小跳跃次数了,这样我们最终实现了将时间复杂度从O(N^2)到O(N)的优化,但是空间复杂度还是O(N)。

class Solution {public:    //DP, s[i]表示能够到达i点所需的最小跳跃次数    //在求解的时候,为了避免重复的计算,当计算到i的时候,其值为num[i],这样可以计算s[i]到s[i+nums[i]]之间    //的最小值,进一步分析可以发现,对于i到i+nums[i]之间的最短跳跃次数的计算,如果,i之前已经计算了,也就是说    //s[i] != INT_MAX,则没必要继续计算该s[i],因为该s[i]一定是最小的值了,所以每到达一个i首先判断i + nums[i]范围    //的值是否已经计算了,如果已经计算了,那么就不需要计算,直接跳过就好,直到 i+nums[i] > curFar,则就应该计算多    //出来的部分,即计算curFar + 1到i + nums[i]之间的部分,这样可以做到算法复杂度达到O(n)    int jump(vector<int>& nums) {int len = nums.size();if (len < 2)return 0;if (len < 3)return 1;int *s = new int[len];s[0] = 0;for (int i = 1; i < len; ++i)s[i] = INT_MAX;int curFar = 0;for (int i = 0; i < len; ++i){   if(i + nums[i] > curFar)   {   for (int j = curFar + 1; j < len && j <= (i + nums[i]); ++j)   {s[j] = s[i] + 1;   }   curFar = i + nums[i];   }      if(curFar >= len - 1)       break;}return s[len - 1];}};


0 0