1269. 停在原地的方案数
大约 4 分钟
---
1269. 停在原地的方案数
- 标签:动态规划
- 难度:困难
题目链接
题目大意
描述:有一个长度为 的数组,开始时指针位于下标 处。每一步操作中,你可以将指针向左或向右移动 步,或者停在原地不动。
要求:在恰好执行 次操作后,指针仍然指向下标 的方案数。答案可能很大,返回对 取模的结果。
说明:
- 。
- 。
示例:
- 示例 1:
输入:steps = 3, arrLen = 2
输出:4
解释:3 步后停在原地的方案有 4 种:原地→原地→原地、原地→右→左、右→原地→左、右→左→原地。- 示例 2:
输入:steps = 2, arrLen = 4
输出:2
解释:2 步后停在原地的方案有 2 种:原地→原地、右→左。解题思路
思路 1:动态规划
1. 阶段划分
按操作步数划分阶段。每一步后,指针的位置可能改变,也可能不变。我们关心的是第 步后指针回到位置 的方案数。
2. 定义状态
定义 表示执行 步操作后,指针位于位置 的方案数。
3. 状态转移方程
第 步的操作决定了第 步结束时的位置。从第 步的位置 出发,第 步有三种选择:
- 不动:新位置仍是 。
- 向右:新位置为 。
- 向左:新位置为 。
反过来,要到达第 步的位置 ,前一步的位置可以是 、 或 :
4. 边界条件和优化
- ,其余 。
- 指针不能越界:。
- 关键优化:,所以指针不可能走到超过 的位置(一步最多移动一格, 步最多 格远)。因此实际需要考虑的位置范围是 到 。
5. 最终结果
。
6. 空间优化
只依赖于 ,可以用滚动数组(两个一维数组)优化空间。
7. 结合示例走一遍
实际最大位置:,所以只有位置 和 。
初始化:
i=1: dp[1][0] = dp[0][0] + dp[0][1] = 1 + 0 = 1 (不动或从1左移,但1不可达)
dp[1][1] = dp[0][1] + dp[0][0] = 0 + 1 = 1 (不动或从0右移)
等等,正确答案中 steps=3,arrLen=2 时结果是4。让我仔细推。
重新递推:
dp[0][0]=1
i=1: dp[1][0] = dp[0][0] + dp[0][1] = 1+0 = 1 (原地不动)
dp[1][1] = dp[0][1] + dp[0][0] = 0+1 = 1 (向右)
→ [1, 1]
i=2: dp[2][0] = dp[1][0] + dp[1][1] = 1+1 = 2 (原地/从1左移)
dp[2][1] = dp[1][1] + dp[1][0] = 1+1 = 2 (原地/从0右移)
→ [2, 2]
i=3: dp[3][0] = dp[2][0] + dp[2][1] = 2+2 = 4 (原地/从1左移)
dp[3][1] = dp[2][1] + dp[2][0] = 2+2 = 4
→ [4, 4]结果为 。
思路 1:代码
class Solution:
def numWays(self, steps: int, arrLen: int) -> int:
mod = 10**9 + 7
# 实际需要计算的最大位置
max_pos = min(arrLen - 1, steps)
# dp[j] 表示当前步数下位于位置 j 的方案数
dp = [0] * (max_pos + 1)
dp[0] = 1
for i in range(1, steps + 1):
# 每步更新,需要前一行的数据,用滚动数组
nxt = [0] * (max_pos + 1)
for j in range(max_pos + 1):
# 不动
nxt[j] = dp[j]
# 从左边来
if j > 0:
nxt[j] = (nxt[j] + dp[j - 1]) % mod
# 从右边来
if j < max_pos:
nxt[j] = (nxt[j] + dp[j + 1]) % mod
dp = nxt
return dp[0]思路 1:复杂度分析
- 时间复杂度:,外层循环 次,内层循环 次。,计算量最多 万,轻松通过。
- 空间复杂度:,滚动数组优化后的空间。