持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
题目描述
有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。
每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。
给你两个整数 steps 和 arrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。
由于答案可能会很大,请返回方案数 模 10^9 + 7 后的结果。
示例 1:
输入:steps = 3, arrLen = 2 输出:4 解释:3 步后,总共有 4 种不同的方法可以停在索引 0 处。 向右,向左,不动 不动,向右,向左 向右,不动,向左 不动,不动,不动
动态规划
动态规划的初步思路是:首先看到这个题目会感觉和找路径题目有点类似,那些题目是有四个方向选择,上下左右,而这题是上,上右,上左。但是有两个特例:就是在最左边的时候和在最右边的时候,在最左边的时候是不能向上左走,在最右边的时候不能向上右走。用动态规划还得好好想想状态方程。首先我们知道能走的最远的位置是步数的一半和长度-1中的较小值。那么我们定义
dp[i][j]定义为当前剩余操作为i,所在位置为j的所有方案数。步骤如下:
- 定义二维dp数组的,i,j的意义,并且进行初始化。
- 推导状态方程:
dp[k][i]=dp[k+1][i]+dp[k+1][i-1]+dp[k+1][i+1](在0,n-1索引处特判一下)- 遍历原则,自底向上的dp:外降内升,加上原地不动的方案数,加上从左向右移动一步的方案数,加上从右到左移动一步的方案数。
- 当消耗完所有步数,位置为0就是最终答案,直接返回
class Solution {
public int numWays(int steps, int arrLen) {
int mod = (int)1e9+7;
int max = Math.min(steps / 2, arrLen - 1);
int[][] dp = new int[steps + 1][max + 1];
dp[steps][0] = 1;
for (int i = steps - 1; i >= 0; i--) {
for (int j = 0; j <= max; j++) {
dp[i][j] = (dp[i][j] + dp[i + 1][j]) % mod;
if (j - 1 >= 0) {
dp[i][j] = (dp[i][j] + dp[i + 1][j - 1]) % mod;
}
if (j + 1 <= max) {
dp[i][j] = (dp[i][j] + dp[i + 1][j + 1]) % mod;
}
}
}
return dp[0][0];
}
}
最后
温馨提示:这道题目使用记忆化dfs也是一种好的思路。每个当前步数和当前位置的方案数由两边和原地的方案数相加,dfs可以巧妙解决数组左右边界问题。使用动态规划的,注意一下边界情况的处理。