LeetCode 55. Jump Game
2016-11-23 21:43
405 查看
本题的大概题意:给定一个整型数组nums,数组的每个值代表能从该位置向前走的最大的步数。一开始时玩家处于数组的第一个位置,问玩家能否到达最后一个位置。
这道题我使用了两种方法,第一种方法是直接使用dp进行搜索:用一个数组vis来表示某个位置是否可达, 若可达则对应值为1,不可达则为0。我们很容易就能发现一个规律:若i 是可达的,那i+1 ~ i + nums[i] 也是可达的。因此,具体实现也很简单,我用的是记忆化搜索的写法,代码如下:
由于测试样例的数据规模并不大,所以这种时间复杂度的算法也能够通过这道题。
但这道题的标签是贪心,说明使用贪心应该有时间复杂度更低的算法。于是我想到了另外一种做法:我们不进行搜索,直接用贪心的做法进行决策。每走到一个新的位置,我们需要选一个“最好”的下一步(所谓最好,就是走了这一步,如果有解的情况下,走这一步一定能达到目的地)。而这“最好”的一步就是再下一步能够去到最远的一步。为什么呢?我们先设当前位置为 i,能够再下一步去到最远的下一步为 j ,则能去到最远的地方为 j + nums[j] 。所有i + 1
~ j - 1 能到达的地方,包括了大于 j 的位置和小于等于j 的位置。对于小于等于j的位置,能到达的最远的地方依然不会超过 j + nums[j] ,这只是“白走了一步”而已;而对于所有大于j 的位置,j 均能够到达,因为j 能够到达所有j + 1 ~ j + nums[j] 的位置,而这些位置其他的下一步不一定能够到达。所以j 是最好的选择。如果走了j之后无法抵达终点,则无解。
具体代码如下,时间复杂度在最差的情况下依然为O(n2),但因为i大部分情况下不需要逐个遍历0 ~ n-1 的每一个值,所以依然加速了不少,通过测试样例的时间是上一种做法的1/10 而已。
这道题我使用了两种方法,第一种方法是直接使用dp进行搜索:用一个数组vis来表示某个位置是否可达, 若可达则对应值为1,不可达则为0。我们很容易就能发现一个规律:若i 是可达的,那i+1 ~ i + nums[i] 也是可达的。因此,具体实现也很简单,我用的是记忆化搜索的写法,代码如下:
const int maxn = 1000 + 50 ; bool vis[maxn] ; void dfs(int x, vector<int>& nums, int n) { if (vis[x] == true) return ; vis[x] = true ; int value = nums[x] ; for (int i=1; i<=value; i++) { int t = i + x ; if (t >= n) return ; dfs(t, nums, n) ; } return ; } class Solution { public: bool canJump(vector<int>& nums) { memset(vis, 0, sizeof(vis)) ; int n = nums.size() ; if (n == 0) return true ; dfs(0, nums, n) ; return vis[n-1] ; } };由于对于每个i , 最多可能要向下搜索n - i 次,所以时间复杂度在最差的情况下,时间复杂度为O(n2) ;
由于测试样例的数据规模并不大,所以这种时间复杂度的算法也能够通过这道题。
但这道题的标签是贪心,说明使用贪心应该有时间复杂度更低的算法。于是我想到了另外一种做法:我们不进行搜索,直接用贪心的做法进行决策。每走到一个新的位置,我们需要选一个“最好”的下一步(所谓最好,就是走了这一步,如果有解的情况下,走这一步一定能达到目的地)。而这“最好”的一步就是再下一步能够去到最远的一步。为什么呢?我们先设当前位置为 i,能够再下一步去到最远的下一步为 j ,则能去到最远的地方为 j + nums[j] 。所有i + 1
~ j - 1 能到达的地方,包括了大于 j 的位置和小于等于j 的位置。对于小于等于j的位置,能到达的最远的地方依然不会超过 j + nums[j] ,这只是“白走了一步”而已;而对于所有大于j 的位置,j 均能够到达,因为j 能够到达所有j + 1 ~ j + nums[j] 的位置,而这些位置其他的下一步不一定能够到达。所以j 是最好的选择。如果走了j之后无法抵达终点,则无解。
具体代码如下,时间复杂度在最差的情况下依然为O(n2),但因为i大部分情况下不需要逐个遍历0 ~ n-1 的每一个值,所以依然加速了不少,通过测试样例的时间是上一种做法的1/10 而已。
class Solution { public: bool canJump(vector<int>& nums) { int n = nums.size() ; if (n == 0) return true ; int i = 0 ; while (i < n) { if (i == n-1 ) return true ; if (nums[i] == 0) return false ; int maxstep = 0 ; int nextstep = i ; for (int j=i+1; j<=i + nums[i] && j < n; j++) { if (maxstep < j - i + nums[j]) { nextstep = j ; maxstep = j - i + nums[j] ; } } i = nextstep ; } return true ; }
相关文章推荐
- 【C++】【LeetCode】55. Jump Game
- LeetCode 55. Jump Game
- Leetcode-55. Jump Game
- LeetCode 55. Jump Game
- 【LeetCode】55. Jump Game
- 【LeetCode】55. Jump Game
- LeetCode 55. Jump Game
- Leetcode 55. Jump Game
- [LeetCode] Algorithms-55. Jump Game
- LeetCode *** 55. Jump Game
- leetcode 55. Jump Game
- LeetCode 55. Jump Game
- Leetcode 55. Jump Game & 45. Jump Game II
- [Leetcode] 55. Jump Game
- [LeetCode]--55. Jump Game
- leetcode题解-55. Jump Game && 56. Merge Intervals
- Leetcode 55. Jump Game
- leetcode - 55. Jump Game
- 算法分析与设计——LeetCode:55. Jump Game
- leetcode.array--55. Jump Game