1.固定步数移动到终点
假设有排成一行的 N 个位置,记为 1~N,N 一定大于等于 2。开始时机器人在其中的 M 位置上,当机器人走到边界时必须往回走(1->2,N->N-1),当走到中间位置时可以往左走或者往右走。规定机器人必须走 K 步,最终停在P位置,问有多少种走法?
暴力递归实现
1 | /** |
暴力递归缓存优化
此实现也可以称为是从顶向下的动态规划/记忆化搜索。
1 | // 实现方式1优化,利用缓存优化暴力递归 |
动态规划实现
动态规划实现思路:直接算出1..n每个点走K步到达目标位置的方案数。
实现方式:
- 先初始化第一列,即剩余步数为0时,只有目标位置方案数为1
- 依次初始化每一列,
- 当前位置在第一行时,只能往右走,也即方案数=数组左下
- 当前位置在最后一行时,只能往左走,也即方案数=数组左上
- 当前位置在中间,可以往左或右走,也即方案数=数组左上+左下
e.g. N=5,目标是4
1 | // 0 1 2 3 4 5 6 剩余步数 |
1 | public static int ways3(int N, int start, int aim, int K) { |
2.预测赢家
给定一个整形数组arr,代表数值不同的纸牌排成一条线(明牌)。玩家A和玩家B依次拿走每张牌,规定玩家A先手,每次取牌时只能拿走最左或最右的牌。玩家A和玩家B都绝顶聪明,每次取牌都会使自己的分数最大化,请返回最后获胜者的分数。
暴力递归实现
1 | // 根据规则,返回获胜者的分数 |
暴力递归缓存优化
1 | public static int win2(int[] arr) { |
动态规划实现
直接推算出数组:
- fmap:每一步先手可以获得最大值
- gmap:每一步后手可以获得最大值
观察暴力递归过程,fmap[L][R]需要借助gmap[L+1][R]和gmap[L][R-1],而gmap[L][R]需要借助
fmap[L+1][R]和fmap[L][R-1]。也就是需要借助对方数组对应位置的左一格和下一格计算。
数组中左下部分是无效的(L>R),L=R对角线已知fmap等于arr[L]、gmap等于0。
接下来只需要对剩下逐级对角线进行计算,即可完成两个数组的推算。
1 | public static int win3(int[] arr) { |