今天闲来没事在力扣上刷算法题,跟一道题就杠上了,把我气得,觉得有必要记录一下。
其实这一道题,一看就是动态规划或递归来做,不过一开始也没仔细去想在这个数据中的递推公式,加上递归写得比较多,自认为比较熟练
深度优先算法(超时)
不一会功夫我就写下了如下代码,麻溜地写出了代码,然后麻溜地超时了
class Solution{
public boolean canJump(int[] nums){
return gotoEnd(0,nums);
}
public boolean gotoEnd(int currentIndex,int[] nums){
if (currentIndex>=nums.length-1) return true;
int jump = nums[currentIndex];
if (jump==0) return false;
boolean b = false;
for (int i = jump-1;i>=0;i--){
int nextIndex = currentIndex+i+1;
b = b||getoEnd(nextIndex,nums);
if(b) reutrn b;
}
return b;
}
}
优化深度优先算法(超时)
很容易看出来上面代码是有很多次递归是在做重复的工作的,因为有可能中途从不同的位置跳到相同的下一个位置,就会导致重复的递归,因此用一人上hashmap记录下在当前位置跳到下一个位置的结果,每次递归前先去查一下是否已经执行过此次跳跃,没有执行过再执行方法
class solution{
Map<Integer,Boolean> map = new HashMap<>();
public boolean canJump(int[] nums){
return gotoEnd(0,nums);
}
public boolean gotoEnd(int currentIndex,int[] nums){
if (currentIndex>=nums.length-1) return true;
int jump = nums[currentIndex];
if (jump==0) return false;
boolean b = false;
for (int i = jump-1;i>=0;i--){
int nextIndex = currentIndex+i+1;
if (map.containsKey(nextIndex))
b = b||map.get(nextIndex);
else {
boolean bb = gotoEnd(nextIndex,nums);
map.put(nextIndex,bb);
b = b||bb;
}
if (b) return b;
}
return b;
}
}
动态规划
上面两个算法都是超时,我也开始思考怎么用动态规划来做,磕磕碰碰做错了很多次,考虑了很多细节,最后写了如下代码,勉强通过题目
class Solution{
public boolean canJump(int[] nums){
if (nums.length<2) return true;
//数组dp[]用来记录dp[i]能到达的最远下标
int[] dp = new int[nums.length];
dp[0] = nums[0];
//end记录最远能跳到哪里,end超过数组长度-1(即数组最大下标)即能跳到终点
int end = nums[0];
for (int i = 1;i<nums.length-1;i++){
//如果到达不了当前位置,就没办法继续往后跳,因而到不了终点
if (dp[i-1]<i) return false;
dp[i] = Math.max(dp[i-1],i+nums[i]);
end = Math.max(dp[i],end);
}
return end>=nums.length-1;
}
}
贴下通过结果和执行时间、内存消耗还有杠上头的提交次数
优化动态规划
题目通过是通过了,不过这数据也太难看了吧,觉得有必要优化优化,不然写这样的代码以后工作迟早得被老板踢出去,
- dp[i]每次只跟dp[i-1]有关,可以把数组简化成一个变量dp
- 简化dp[]数组后,dp变量其实就是表示数组能到达的最远下标,其实就是end变量的作用,因此dp变量直接替代了end变量,end变量可以删除
- 不一定要循环遍历完一遍数组再返回结果,如果中途就发现能到达的最远下标不小于数组最大下标,则能提前返回结果
class Solution {
public boolean canJump(int[] nums){
if (nums.length<2) return true;
int dp = nums[0];
for (int i = 1;i<nums.length-1;i++){
if (dp<i) return false;
dp = Math.max(dp,i+nums[i]);
if(dp>=nums.length-1) return true;
}
return dp>=nums.length-1;
}
}
最后时间优化了一半,内存消耗还是一点没少,估计也因为是编程语言是Java吧哈哈哈哈