一、题目描述
有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。
每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。
给你两个整数 steps 和 arrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。
由于答案可能会很大,请返回方案数 模 10^9 + 7 后的结果。
提示:
- 1 <= steps <= 500
- 1 <= arrLen <= 10^6
二、题解
动态规划问题,题解如下:
//dp[i][j]表示走i步,从位置j到位置0的方案数
//初始化:dp[0][0] = 1,其余dp[i][j] = 0
//伪代码:
int mode = 1000000007
for i = 1; i<= steps; ++i:
for j = 0; j< maxStep; ++j:
if j-1 >= 0 && j+1 < maxStep && !dp[i-1][j] && !dp[i-1][j-1] && !dp[i-1][j+1]:
break
else:
dp[i][j] += dp[i-1][j] //花费一步原地不动,再花费i-1步到位置0
dp[i][j] %= mode
if j-1 >= 0:
dp[i][j] += dp[i-1][j-1] //花费一步往左走,再从左边位置j-1花费i-1步到位置0
dp[i][j] %= mode
if j+1 < maxStep:
dp[i][j] += dp[i-1][j+1] //花费一步往右走,再从右边位置j+1花费i-1步到位置0
dp[i][j] %= mode
return dp[steps][0]
性能分析
时间复杂度:O(steps*min(steps/2,arrLen-1))
说明:两层嵌套遍历,第一层是steps,第二层是min(steps/2,arrLen-1)。
空间复杂度:O(steps*min(steps/2,arrLen-1))
说明:dp二维数组是(steps+1)*(min(steps/2,arrLen-1)+1)。
结果
三、总结
大概花了1个小时左右,还是得多做动态规划类型的题目,并且在最短时间内理清dp数组的定义和写出状态转移方程才行!
四、代码
#include <bits/stdc++.h>
using namespace std;
int mode = 1000000007;
int numWays(int steps, int arrLen) {
int maxStep = min(steps/2,arrLen-1) + 1;
vector<vector<int>> dp(steps+1,vector<int>(maxStep,0));
dp[0][0] = 1;
for (int i = 1; i<= steps; ++i) {
for (int j = 0; j< maxStep; ++j) {
if(j-1 >= 0 && j+1 < maxStep && !dp[i-1][j] && !dp[i-1][j-1] && !dp[i-1][j+1]){
break;
}else{
dp[i][j] += dp[i-1][j];
dp[i][j] %= mode;
if(j-1 >= 0){
dp[i][j] += dp[i-1][j-1];
dp[i][j] %= mode;
}
if(j+1 < maxStep){
dp[i][j] += dp[i-1][j+1];
dp[i][j] %= mode;
}
}
}
}
return dp[steps][0];
}
int main() {
cout<<numWays(27,7);
return 0;
}