当前位置: 代码迷 >> 综合 >> LeetCode每日一题: 1269. 停在原地的方案数
  详细解决方案

LeetCode每日一题: 1269. 停在原地的方案数

热度:49   发布时间:2023-12-08 10:35:04.0

1269. 停在原地的方案数

题目

有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。

每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。

给你两个整数 stepsarrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。

由于答案可能会很大,请返回方案数 10^9 + 7 后的结果。

示例 1:

输入:steps = 3, arrLen = 2
输出:4
解释:3 步后,总共有 4 种不同的方法可以停在索引 0 处。
向右,向左,不动
不动,向右,向左
向右,不动,向左
不动,不动,不动

提示:

  • 1 <= steps <= 500
  • 1 <= arrLen <= 10^6

思路

这题的话不算太难,思路理清楚基本上还是可以做出来的。总共就三种状态转移方式,左移右移和不动,然后分三种情况:最左边最右边和中间的就行了。难的感觉反而还是时间和空间上的优化吧。空间优化的话就不展开了,新建数组或变量保存原来的值就可以了,就是会麻烦点。

上代码!

代码

static final int M = 1000000007;public int numWays(int steps, int arrLen) {
    // 最远只能移动到steps/2,再远就回不到原点了;// 取两者最小值即可(arrLen要-1,因为len代表数组下标最末尾的值)int len = Math.min(steps / 2, arrLen - 1);// dp[i][j]表示一共i步下经过j的位置返回0有多少种移动方案(好像有点难理解哈= =)int[][] dp = new int[steps + 1][len + 1];// 初值为1dp[0][0] = 1;for (int i = 1; i <= steps; i++) {
    // 枚举步数// 因为最远也只能走i步,所以取两者最小值可以减少j的循环次数(时间优化)// 不能取i/2,因为后续状态转移会用到走i步的值int x = Math.min(i, len);// 不进行优化的话j<=len即可for (int j = 0; j <= x; j++) {
    // 在0处只能从右边或原地移动过来if (j == 0) {
    dp[i][j] = (dp[i - 1][j] + dp[i - 1][j + 1]) % M;} else if (j == len) {
    // 最右边只能从左边或原地过来(注意是len,即数组最末尾)dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % M;} else {
    // 正常转移,可以从左边、右边或原地移动过来(加一次取余一次,不然数据会超限)dp[i][j] = ((dp[i - 1][j - 1] + dp[i - 1][j]) % M + dp[i - 1][j + 1]) % M;}}}return dp[steps][0];
}