903. Valid Permutations for DI Sequence
題目網址:https://leetcode.cn/problems/valid-permutations-for-di-sequence/
題意:給一長度為
n的 strings, 其中s[i]可能是:
D代表減少I代表增加有效排列是對在
[0, n]範圍內的所有整數的一個排列perm, 使得對所有的i滿足以下規則:
- 若
s[i] == 'D', 則perm[i] > perm[i + 1]- 若
s[i] == 'I', 則perm[i] < perm[i + 1]返回有效排列
perm的數量, 因為答案可能很大, 所以請返回你的答案對$10^9 + 7$取餘數。

Solution 1:
想法:利用 DP, 由於
s[i]決定的只是perm中的「相對」大小, 故perm[i]的值僅由s[i - 1]和perm[i - 1]決定。1. 定義狀態:
- 首先, 會在
s前先加上一個#, 代表什麼元素都沒有的狀態dp[i][j]:s[1:i]中, 結尾為perm[i] = j的有效排列數。其中0 ≤ j ≤ i
➔ 相當於是[0, i]的有效排列數2. 得到轉移方程:
- 若
s[i] == 'I', 因perm[i] = j, 所以有效排列數為加總前一個數s[i - 1]在區間[0, j - 1]的有效排列數
➔dp[i][j] = sum(dp[i - 1][k]), for0 ≤ k ≤ j - 1- 若
s[i] == 'D', 因perm[i] = j, 那有效排列數是不是為加總前一個數s[i - 1]在區間[j + 1, i]的有效排列數呢?其實不是,s[i - 1]要改成在區間[j, i]才對
➔dp[i][j] = sum(dp[i - 1][k]), forj ≤ k ≤ i
理由如下, 假如我們現在已經有了一個
"DID"的排列1032。若我們還想加一個D, 將其變成"DIDD"的排列, 應該如何加數字呢?多了一個數字4, 但顯然直接加4是不行的
- 可以在末尾加
2, 但是要先把原排列中≥ 2的數字都先+1, 即1032➔1043, 然後再加2, 變成10432- 也可以在末尾加
1, 但是要先把原排列中≥ 1的數字都先+1, 即1032➔2043, 然後再加1, 變成20431- 也可以在末尾加
0, 但是要先把原排列中≥ 0的數字都先+1, 即1032➔2143, 然後再加0, 變成21430- 但是, 無法再末尾加
3或4, 因為原排列中的最後一位為2, 所以只有≤ 2的數能被加在末尾, 否則無法形成降序(s = "DIDD", 最後必須是降序)➔ 故
k的區間為[j, i], 其中j為原排列的末尾perm[i - 1]之值3. 初始化:
dp[0][0]:當範圍為[0, 0]時, 只有1種有效排列數
➔dp[0][0] = 1- 其餘皆初始成
0題目要求的是所有有效的排列數, 故答案為加總最後一位所有的可能性
class Solution { |
- time:$O(n^2)$ ➔ for loop
- space:$O(n^2)$ ➔
dp
Solution 2:
想法:改進 Solution 1, 由於
dp[i][j]只會用到上一列的狀態, 故只需儲存上一列的狀態即可
class Solution { |
- time:$O(n^2)$ ➔ for loop
- space:$O(n)$ ➔
dp,prevRow
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 Zako's Blog!
評論