一、Problem
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.
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
Constraints:
1 <= steps <= 500
1 <= arrLen <= 10^6
二、Solution
方法一:記憶化 + 剪枝
這是我一開始的想法,但是遇到了許多坑:
溢出坑:a、b、c 的值都如果到了 1e9,那麼三數相加一定會爆 int,這是第一版代碼
class Solution {
int N, MOD = (int) 1e9+7, f[][];
int dfs(int i, int s) {
if (i < 0 || i >= N)
return 0;
if (i != 0 && s <= 0)
return 0;
if (i == 0 && s == 0)
return 1;
if (f[i][s] != 0)
return f[i][s];
int a = dfs(i-1, s-1), b = dfs(i, s-1), c = dfs(i+1, s-1);
return f[i][s] = (a + b + c) % MOD;
}
public int numWays(int steps, int arrLen) {
N = arrLen;
f = new int[N+1][steps+1];
dfs(0, steps);
return f[0][steps];
}
}
超時坑:將 int 改爲 long 之後,發現我需要剪枝了
class Solution {
int N;
long MOD = (long) 1e9+7, f[][];
long dfs(int i, int s) {
if (i < 0 || i >= N)
return 0;
if (i != 0 && s <= 0)
return 0;
if (i == 0 && s == 0)
return 1;
if (f[i][s] != 0)
return f[i][s] % MOD;
long a = dfs(i-1, s-1) % MOD, b = dfs(i, s-1) % MOD, c = dfs(i+1, s-1) % MOD;
return f[i][s] = (a + b + c) % MOD;
}
public int numWays(int steps, int arrLen) {
N = arrLen;
f = new long[N+1][steps+1];
dfs(0, steps);
return (int)f[0][steps];
}
}
超時2,剪枝後:當 i > s 時 無論如何,i 都回不到 0 位置了,所以當 i > s 時,返回 0 即可,但還是超時…
class Solution {
int N;
long MOD = (long) 1e9+7, f[][];
long dfs(int i, int s) {
if (i < 0 || i >= N)
return 0;
if (i > s)
return 0;
if (i == 0 && s == 0)
return 1;
if (f[i][s] != 0)
return f[i][s] % MOD;
long a = dfs(i-1, s-1) % MOD, b = dfs(i, s-1) % MOD, c = dfs(i+1, s-1) % MOD;
return f[i][s] = (a + b + c) % MOD;
}
public int numWays(int steps, int arrLen) {
N = arrLen;
f = new long[N+1][steps+1];
dfs(0, steps);
return (int)f[0][steps];
}
}
最後發現我真的被坑埋了,看了 steps 才 500,但 arrLen卻有 這麼大,咋話,如果 steps = 500,那麼走過的步數大於 250 都是回不來的了。
最後 WA 了 3 次,勉強過了…
class Solution {
int N;
long MOD = (long) 1e9+7, f[][];
long dfs(int i, int s) {
if (i < 0 || i >= N)
return 0;
if (i > s)
return 0;
if (i == 0 && s == 0)
return 1;
if (f[i][s] != 0)
return f[i][s] % MOD;
long a = dfs(i-1, s-1) % MOD, b = dfs(i, s-1) % MOD, c = dfs(i+1, s-1) % MOD;
return f[i][s] = (a + b + c) % MOD;
}
public int numWays(int steps, int arrLen) {
N = Math.min(arrLen, steps/2+1);
f = new long[N+1][steps+1];
dfs(0, steps);
return (int)f[0][steps];
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
方法二:dp
- 定義狀態:
- 表示走了 步,然後到達 位置的方案數。
- 思考初始化:
- 停留在原地必定有一種方案
- 思考狀態轉移方程:
- 思考輸出:
class Solution {
public int numWays(int steps, int N) {
N = Math.min(N, steps/2+1);
int mod = (int) 1e9+7, f[][] = new int[steps+1][N];
f[0][0] = 1;
for (int i = 1; i <= steps; i++)
for (int j = 0; j < N; j++) {
f[i][j] = f[i-1][j];
if (j > 0) f[i][j] = (f[i][j] + f[i-1][j-1]) % mod;
if (j+1 < N) f[i][j] = (f[i][j] + f[i-1][j+1]) % mod;
}
return f[steps][0];
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,