题目
有一个长度为 arrLen 的数组,开始有一个指针在索引 0 处。
每一步操作中,你可以将指针向左或向右移动 1 步,或者停在原地(指针不能被移动到数组范围外)。
给你两个整数 steps 和 arrLen ,请你计算并返回:在恰好执行 steps 次操作以后,指针仍然指向索引 0 处的方案数。
由于答案可能会很大,请返回方案数 模 10^9 + 7 后的结果。
提示:
1 <= steps <= 500
1 <= arrLen <= 10^6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
因为之前草草看了动态规划隐约觉的很像,但是又不熟,于是想用数学硬推,发现推不出来(微笑脸)。。简单放下思路代码吧。研究动态规划去了。
class Solution {
public:
int numWays(int steps, int arrLen) {
//需要满足以下条件:
//steps = right+left+stay
//right = left < arrLen
//right必须出现在left之前
int result = 1;
for(int stay=steps;stay>=0;){
int move = steps-stay;
if(move == 0) {
stay = stay-2;
continue;
};
//moveop是移动可能出现的位置。
int moveop = 1;
for(int i=0;i<move;i++){
moveop = moveop*(steps-i)/(i+1);
}
moveop = moveop%((int)pow(10,9)+7);
//每个move可以是left或者right,right在前和left在前的概率应该是对半的(x,思路不对)
moveop = moveop*((int)pow(2,(move/2)-1)%(int)(pow(10,9)+7));
result = result+moveop;
stay = stay-2;
}
return result;
}
};
动态规划
定义 f[i][j] 代表当前剩余操作数为 i,所在位置为 j 的所有方案数。
起始位置为 0,操作次数为 step,即有初始化条件 f[step][0]=1,f[0][0] 则是我们的最终答案。
不失一般性的考虑 f[i][j]可以由哪些状态转移而来:
由「原地」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j] 转移而来
由「向左」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j+1] 转移而来
由「向右」操作到达当前状态,消耗一次操作,此时由状态f[i+1][j−1] 转移而来
求的是方案数,即最终的f[i][j] 为三者累加值。
同时我们发现 f[i][x] 依赖于f[i+1][y],因此我们需要按照「step 从大到小」的顺序进行转移。
同时我们根据「最终回到下标 0 位置」可以推断出,最远到达的位置为 step / 2(再远就回不来了)。将最远到达位置与数组最大下标取 minmin 即可确定维度 step的范围。
作者:AC_OIer
链接:https://leetcode-cn.com/problems/number-of-ways-to-stay-in-the-same-place-after-some-steps/solution/gong-shui-san-xie-xiang-jie-xian-xing-dp-m9q9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复盘
class Solution {
public:
const int MODULO = 1000000007;
int numWays(int steps, int arrLen) {
//定义 dp[i][j] 代表当前剩余操作数为 i,所在位置为 j 的所有方案数
int maxColumn = min(steps/2,arrLen-1);
vector<vector<int>> dp(steps + 1, vector<int>(maxColumn + 1));
dp[steps][0] = 1;
for(int i = steps-1;i>=0;i--){
for(int j = 0;j<=maxColumn;j++){
//加原地不动的方案
dp[i][j] =(dp[i][j]+dp[i+1][j])%MODULO;
//加从左边来的方案
if(j-1>=0) dp[i][j] = (dp[i][j]+dp[i+1][j-1])%MODULO;
//加从右边来的方案
if(j+1<=maxColumn) dp[i][j] = (dp[i][j]+dp[i+1][j+1])%MODULO;
}
}
return dp[0][0];
}
};
时间复杂度:共有数量级为 step * maxstep∗max 个的状态需要被转移。复杂度为 O(step * max)O(step∗max)
空间复杂度:O(step * max)O(step∗max)
改进
后面补