leetcode 55. Jump Game
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.
方法一:回溯法
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int len = nums.size(); 5 return canJump(0, nums, len - 1); 6 } 7 private: 8 bool canJump(int position, vector<int> nums, int destination) { 9 if (position == destination) { 10 return true; 11 } 12 int furtherJump = min(destination, position + nums[position]); 13 //遍历所有能到达的下一个位置 14 for (int nextposition = furtherJump; nextposition > position; nextposition--) { 15 //for (int nextposition = position + 1; nextposition <= furtherJump; nextposition++) { 16 //其中有一个位置到达了最后,返回true 17 if (canJump(nextposition, nums, destination)) { 18 return true; 19 } 20 } 21 return false; 22 } 23 };
时间复杂度:O(2n), 空间复杂度:O(n)
方法二:记忆化递归,当知道某一位置可以/不可以到达目的地时,直接记录,下次再访问这个位置时,直接返回。
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int len = nums.size(); 5 //int *dp = new int[len]; 6 vector<int> memo(len, -1); 7 //memo[len - 1] = 1; //1表示 8 return canJump(0, nums, len - 1, memo); 9 } 10 private: 11 bool canJump(int position, vector<int> nums, int destination, vector<int> &memo) { 12 if (position == destination) //到达最后一个位置,返回true 13 return true; 14 if (memo[position] >= 0) { //如果之前记录过这个位置可以/不可以到达,直接返回状态 15 (memo[position] == 1) ? true : false; 16 } 17 int furtherJump = min(destination, position + nums[position]); 18 for (int nextposition = position + 1; nextposition <= furtherJump; nextposition++) { 19 if (canJump(nextposition, nums, destination, memo)) { 20 memo[position] = 1; 21 return true; 22 } 23 } 24 memo[position] = 0; 25 return false; 26 } 27 };
时间复杂度:O(n2), 空间复杂度:O(2n)=O(n)
方法三:动态规划
(1)对上面记忆话dfs去掉递归
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int len = nums.size(); 5 vector<bool> dp(len, false); 6 dp[len - 1] = true; //标记最后一个位置可达 7 for (int i = len - 2; i >= 0; i--) { //从后往前判断每一个点是否可达 8 int furtherJump = min(len - 1, i + nums[i]); //在第i个位置可以跳的最远步数 9 for (int nextposition = i + 1; nextposition <= furtherJump; nextposition++) { 10 if (dp[nextposition] == true) { //只要跳到后面任一个可达的位置,那么i就是可达的 11 dp[i] = true; 12 break; 13 } 14 } 15 } 16 return dp[0]; 17 } 18 };
时间复杂度:O(n2), 空间复杂度:O(2n)=O(n)
(2)分析:设立distance为当处在i下标的时候,前面所能够达到的所有长度的最大值(因为是最大值,所以0~最大值的所有下标都可以遍历到),当i <= distance的所有下标都可以遍历,然后更新distance的值为distance = max(distance, i + nums[i]);
最后判断能够最远到达的distance是否够的到最后一个下标n-1,不能的话返回false,能的话返回true
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int distance = 0; 5 int len = nums.size(); 6 for (int i = 0; i < len - 1 && i <= distance; i++) { 7 distance = max(distance, i + nums[i]); 8 } 9 return (distance >= len - 1); 10 } 11 };
方法四:贪心
我们用一个变量pos指向数组最左端能够跳到下标n-1的位置,从末尾开始向左遍历所有位置,如果它能跳到的最右端>=pos,那么更新pos,初始化pos=n-1;
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int lastPos = nums.size() - 1; 5 for (int i = nums.size() - 2; i >= 0; i--) { 6 if (i + nums[i] >= lastPos) 7 lastPos = i; 8 } 9 return (lastPos == 0); 10 } 11 };
越努力,越幸运