LeetCode破解之停在原地的方案数

82 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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可以巧妙解决数组左右边界问题。使用动态规划的,注意一下边界情况的处理。