【遞推型 dp】B003_LC_停在原地的方案數(記憶化 / dp)

一、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卻有 10610^6 這麼大,咋話,如果 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];
    }
}

複雜度分析

  • 時間複雜度:O(n×steps)O(n × steps)
  • 空間複雜度:O(n×steps)O(n × steps)

方法二:dp

  • 定義狀態
    • f[i][j]f[i][j] 表示走了 ii 步,然後到達 jj 位置的方案數。
  • 思考初始化:
    • f[0][0]=1f[0][0] = 1 停留在原地必定有一種方案
  • 思考狀態轉移方程
    • f[i][j] =f[i1][j]f[i][j]\ = f[i-1][j]
    • f[i][j] +=f[i1][j1]f[i][j]\ += f[i-1][j-1]
    • f[i][j] +=f[i1][j+1]f[i][j]\ += f[i-1][j+1]
  • 思考輸出f[steps][0]f[steps][0]
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];
    }
}

複雜度分析

  • 時間複雜度:O(N×steps)O(N × steps)
  • 空間複雜度:O(N×steps)O(N × steps)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章