第一个参数int N,有N个位置1,2,3,4~N,N>1
第二个参数int S,开始位置,有个机器人停在哪个位置上,是1~N中间的。
第三个参数int E,是目标位置,从S出发到E
第四个参数int K,机器人必须走K步,要想从S到达E,有多少种方法?可以随意向左向右走
public static int ways1(int N, int start, int aim, int K) {
if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
return -1;
}
return process1(N,aim,start,K );
}
// 有哪些位置?1~N 固定参数
// 最终的目标是aim, 固定参数
// 机器人当前来到的位置是cur,可变参数
// 机器人还有rest步需要去走, 可变参数
// 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
// 当可变参数确定,返回值确定
// 暴力递归版本 O(2^k)
public static int process1(int N, int aim, int cur, int rest ) {
if (rest == 0) { // 如果已经不需要走了,走完了! basecase
return cur == aim ? 1 : 0; // 剩0步到达aim就是一种方法
}
// 还有路可以走
// rest>0 ,来到1,必须1→2,还剩rest-1。
if (cur == 1) { // 1 -> 2
return process1(N ,aim, 2, rest - 1 );
}
// 来到N,没有选择只能N-1后退, 还剩rest-1
if (cur == N) { // N-1 <- N
return process1(N ,aim, N - 1, rest - 1 );
}
// 机器人来到中间位置,有两种选择,往左迈一步,往右迈一步。
return process1(N ,aim,cur - 1, rest - 1) + process1( N ,aim, cur + 1, rest - 1);
}
// 记忆化搜索,搞定可变参数组合 O(KxN)
public static int ways2(int N, int start, int aim, int K) {
if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
return -1;
}
// 开多大分析可变参数范围,0~K,K+1, 1~N,N+1,0位置是无法到达的
int[][] dp = new int[N + 1][K + 1];
// 初始化都置成-1,不是-1就代表计算过,直接返回。
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= K; j++) {
dp[i][j] = -1;
}
}
// dp就是缓存表
// dp[cur][rest] == -1 -> process1(cur, rest)之前没算过!
// dp[cur][rest] != -1 -> process1(cur, rest)之前算过!返回值,dp[cur][rest]
// N+1 * K+1
return process2(start, K, aim, N, dp);
}
// cur 范: 1 ~ N
// rest 范:0 ~ K
public static int process2(int cur, int rest, int aim, int N, int[][] dp) {
if (dp[cur][rest] != -1) { // 状态计算过返回
return dp[cur][rest];
}
// 之前没算过!缓存没命中 尝试
if (rest == 0) {
dp[rest][cur] = cur == aim ? 1 : 0; // 记忆
return dp[cur][rest];
}
// rest >0 有路可走
if (cur == 1) {
dp[rest][cur] = process2(2, rest - 1, aim, N, dp);// 记忆
} else if (cur == N) {
dp[rest][cur] = process2(N - 1, rest - 1, aim, N, dp);// 记忆
} else {
dp[rest][cur] = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);// 记忆
}
return dp[cur][rest];
}
// DP 改递归代码从格子取值
public static int ways3(int N, int start, int aim, int K) {
if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
return -1;
}
int[][] dp = new int[N + 1][K + 1];
dp[aim][0] = 1;
for (int rest = 1; rest <= K; rest++) {
dp[1][rest] = dp[2][rest - 1];
for (int cur = 2; cur < N; cur++) {
dp[cur][rest] = dp[cur - 1][rest - 1] + dp[cur + 1][rest - 1];
}
dp[N][rest] = dp[N - 1][rest - 1];
}
return dp[start][K];
}