LeetCode No.45 JumpGame 2 题解

来源:互联网 发布:4g网络能玩英雄联盟吗 编辑:程序博客网 时间:2024/05/21 01:31

LeetCode No.45 JumpGame 2 题解

题目描述


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

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


题目分析

题目的大概意思就是给出一个从每个点最多能向前跳的步数, 问至少需要多少步能够跳到数组尾端。
这个最多要引起注意。 之前没有仔细思考, 认为这是一道DP题。 不过这仍不失为一种解法(虽然时间复杂度来说不够好)

那么首先看DP是怎么解的。

方法一 DP求解

首先我们注意到这道题显然是具有一定的最优子问题结构的。即可以通过某种局部最优的情况下进行状态转移达到
一个全局最优。
状态转移方程也十分显然。如下:
step[n + k] = min(step[n + k], step[n] + 1), for any k = 1,2,... , a[n]
时间复杂度为:O(n * k) , 其中 k 为每个点最长步数的平均值。

由于实际实现不复杂, 加上不是好的解法, 就不贴代码了(事实上我开始这么写完拿去Judge发现TLE了 :)

方法二 贪心求解

首先来看DP是在什么情况下表现比较糟糕的。 即每个点的步数都很大时, 时间复杂度退化为(n * n).再来考虑为什么会复杂度高(即看是否存在着重复运算)
举一个简单的例子:
a[n] = [6,5,4,3,2,1,1,1]
这个例子几乎就是造成DP超时的例子的简化版。
不难发现其实造成了大量的不必要计算。 比如在处理完a[0]之后, 处理a[1]时,从a[1 + 1] ~ a[0 + a[0]]这部分的比较是不必要的, 因为显然之前能够直达的话就不可能更新到更小的值。
于是自然就会产生一个想法:把每一步能够到达的最大点的坐标记录下来,下一步能够到达的最大点的坐标一定只能从当前步数能到达的最大点来得到, 而不是从之前就已经能够到的最大点来得到。
语言描述比较无力, 下面是体现这种想法的主要计算式:
max[i] = maximum(nums from max[i - 2] to max[i - 1]);
没有做很严谨的分析, 从直觉上说, 这种做法的主要改进就是记忆化了max数组从而可以设置了搜索的下界。
时间复杂度优化为了O(n)算是一个不错的改进了。
之后我看了一下这道题分类放在Greedy里面,想一下这种方法叫做贪心未尝不可。 但我觉得这种基于状态保存的思想还是更像是DP :)
下面上代码,十分简短。 就喜欢这种代码量不多又有一定trick的题目 ~.~


class Solution {public:    int jump(vector<int>& nums) {        if (nums.size() == 1) return 0;        if (nums[0] >= nums.size() - 1) return 1;        int max[nums.size()];        for (int i = 0; i < nums.size(); ++i) {            max[i] = 0;        }        max[0] = 0; max[1] = nums[0];        for (int i = 2; i < nums.size(); ++i) {            max[i] = maximum(nums, max[i - 2], max[i - 1]);            if (max[i] >= nums.size() - 1) return i;        }    }    int maximum(vector<int> &nums, int st, int ed) {        int ans = 0;        for (int i = st; i <= ed; ++i) {            if (nums[i] + i > ans) ans = nums[i] + i;        }        return ans;    }};

其他细节

  • 注意边界条件判断。LeetCode 每道题几乎都有边界的测试。实在服气。
  • 像诸如vector这种,还是尽量用引用传递吧。 虽然没试过, 但是感觉不传引用就是TLE…

The End.

原创粉丝点击