LeetCode全集请参考:LeetCode Github 大全
题目
1269. Number of Ways to Stay in the Same Place After Some Steps
You have a pointer at index 0 in an array of size arrLen. At each step, you can move 1 position to the left, 1 position to the right in the array or stay in the same place (The pointer should not be placed outside the array at any time).
Given two integers steps and arrLen, return the number of ways such that your pointer still at index 0 after exactly steps steps.
Since the answer may be too large, return it modulo 10^9 + 7.
Example 1:
Input: steps = 3, arrLen = 2
Output: 4
Explanation: There are 4 differents ways to stay at index 0 after 3 steps.
Right, Left, Stay
Stay, Right, Left
Right, Stay, Left
Stay, Stay, Stay
Example 2:
Input: steps = 2, arrLen = 4
Output: 2
Explanation: There are 2 differents ways to stay at index 0 after 2 steps
Right, Left
Stay, Stay
Example 3:
Input: steps = 4, arrLen = 2
Output: 8
Constraints:
1 <= steps <= 500
1 <= arrLen <= 10^6
回溯递归解决
分析:移动的三种方案可以转换为数字右移+1
,不动0
,左移-1
。 很容易就想到用回溯递归的方式解决。退出的条件有两个:
- 步数用完
steps == 0
,如果位置为0则表示一种方案,返回1,否则表示不符合要求,返回0; - 超过边界
sum < 0 || sum >= arrLen
,实际上还有优化的空间最大步数不超过steps的一半,或者arrLen。Math.min(steps/2 + 1, arrLen)
public int numWays(int steps, int arrLen) {
return helper(steps, arrLen, 0);
}
private int helper(int steps, int arrLen, int sum) {
// check edge
if (sum < 0 || sum >= arrLen) {
return 0;
}
// exit
if (steps == 0) {
return sum == 0 ? 1 : 0;
}
int next = steps - 1;
return helper(next, arrLen, sum + 1) + helper(next, arrLen, sum) + helper(next, arrLen, sum - 1);
}
这里不考虑时间复杂度,可以解决问题,在LeetCode提交会超时。
动态规划
如果我们将dp状态选择为dp[steps][position]
,则可以从该状态选择:
- 不动。然后我们消耗一步,并停留在同一位置=>
dp[steps-1][position]
- 向右走。然后,我们走了一步,然后向右走=>
dp[steps-1][position+1]
- 向左走(如果不在零位置)。然后我们消耗一步,然后向左走=>
if position > 0 then dp[steps-1][position-1]
然后我们的状态可以计算为:dp[steps][position] = dp[steps-1][position] + dp[steps-1][position+1] + dp[steps-1][position-1]
。
当只有一步作为基本案例时,我们可以使用该案例。这些情况是:
- 我们处于零位,只有一步,那么只有一种方法(停留)=>
dp[1][0] = 1
- 我们处于第一位置,只有一步,然后只有一种方法(向左走)=>
dp[1][1] = 1
请注意,我们只能进行尽可能多的步骤。例如,对于500步,我们只能到达第500个位置,而arrLen是否为99999999则无关紧要。因此,我们使用它来避免内存/时间限制。min(steps,arrLen)
public int numWaysWithDP(int steps, int arrLen) {
//int MOD = 1000_000_007;
final int MOD = (int)1e9 + 7;
int maxPos = Math.min(steps / 2 + 1, arrLen);
long[][] dp = new long[steps + 1][maxPos + 1];
dp[1][0] = 1;
dp[1][1] = 1;
for (int i = 2; i <= steps; i++) {
for (int k = 0; k < maxPos; k++) {
dp[i][k] = (dp[i - 1][k] + dp[i - 1][k + 1] + (k > 0 ? dp[i - 1][k - 1] : 0)) % MOD;
}
}
return (int) dp[steps][0];
}