【递归到动态规划】: 机器人走格子问题

题目

在这里插入图片描述

代码

递归版

public static int ways1(int N, int start, int aim, int K) {
	//参数无效直接返回0
	if (N < 2 || start < 1 || start > N || aim < 1 || aim > N || K < 1) {
		return -1;
	}
	//总共N个位置,从M点出发,还剩K步,返回最终能到达P的方法数
	return process1(start, K, aim, N);
}

// 机器人当前来到的位置是cur,
// 机器人还有rest步需要去走,
// 最终的目标是aim,
// 有哪些位置?1~N
// 返回:机器人从cur出发,走过rest步之后,最终停在aim的方法数,是多少?
public static int process1(int cur, int rest, int aim, int N) {
	if (rest == 0) { // 如果已经不需要走了,走完了!
		return cur == aim ? 1 : 0;
	}
	// (cur, rest)
	if (cur == 1) { // 1 -> 2
		return process1(2, rest - 1, aim, N);
	}
	// (cur, rest)
	if (cur == N) { // N-1 <- N
		return process1(N - 1, rest - 1, aim, N);
	}
	// (cur, rest)
	return process1(cur - 1, rest - 1, aim, N) + process1(cur + 1, rest - 1, aim, N);
}

缓存版

暴力递归会多余相同的计算,所以当递归状态相同时候,直接返回缓存值。

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; 
	}
	int[][] dp = new int[N + 1][K + 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];
	}
	// 之前没算过!
	int ans = 0;
	if (rest == 0) {
		ans = cur == aim ? 1 : 0;
	} else if (cur == 1) {
		ans = process2(2, rest - 1, aim, N, dp);
	} else if (cur == N) {
		ans = process2(N - 1, rest - 1, aim, N, dp);
	} else {
		ans = process2(cur - 1, rest - 1, aim, N, dp) + process2(cur + 1, rest - 1, aim, N, dp);
	}
	dp[cur][rest] = ans;//先加缓存再返回
	return ans;

}

动态规划版

直接舍弃递归,用二维数组代替状态。但是这个二维数组是之前暴力递归推到出来的。

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];
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值