题目
解题思路
这道题第一眼看上去就能想到要用递归,因此可以先写出递归的实现代码,但别提交因为递归的时间复杂度很高,此题又是困难题,因此暴力递归肯定时间超时。所以为了保证我们的通过率,还应再次基础上进行记忆化搜索来优化算法。
递归第一步先考虑怎么出来,此题结束递归的条件为判断当前位置经过{k-1,k,k+1}步能不能刚好到达最后一颗石子,即stones[i] + (k-1 || k || k+1) == stones[stones.lenth - 1];
第二步考虑怎么进行递归,当我们通过k步来到第stones[i]块石头的位置,考虑能否经过{k-1,k,k+1}步刚好到达有石头的地方,如果有再继续遍历。
之后优化。
首先我们需要知道我们要保存的东西是什么。应该是当我来到第i块石头要向前走m步的时候我想知道先前的递归是不是已经有过这样子的先例如果有,那么直接根据之前的结果返回上一层,不需要继续往下递归,从而节省时间。
比起动态规划,递归+记忆化搜索是一种比较好想到的算法,唯一的缺点就是代码量可能比较长.
代码
//递归+记忆化搜索(Myself)
class Solution {
int[][] dp;
public boolean canCross(int[] stones) {
dp = new int[stones.length][stones.length];
return path(stones, 1, 0);
}
public boolean path(int[] stones, int k, int count) {
int n = stones.length;
boolean flag = false;
if(dp[count][k] > 0) {
return true;
}else if(dp[count][k] < 0) {
return false;
}
if(stones[count] + k == stones[n - 1]) {
return true;
}
if((stones[count] + k) >= stones[count + 1]) {
for (int i = count + 1; i < n; i++){
if((stones[count] + k) == stones[i]) {
flag = path(stones, k-1, i);
dp[i][k-1] = flag == false ? -1 : 1;
if (flag){
break;
}
flag = path(stones, k, i);
dp[i][k] = flag == false ? -1 : 1;
if (flag){
break;
}
flag = path(stones, k+1, i);
dp[i][k+1] = flag == false ? -1 : 1;
break;
}
}
}
return flag;
}
}