DI 序列的有效排列
难度:
标签:
题目描述
代码结果
运行时间: 40 ms, 内存: 16.0 MB
/*
* Problem: Given a string 's' of length n where 's[i]' is:
* - 'D' means decreasing
* - 'I' means increasing
* A valid permutation is a permutation of numbers [0, 1, ..., n] that satisfies:
* - If s[i] == 'D', then perm[i] > perm[i+1]
* - If s[i] == 'I', then perm[i] < perm[i+1]
* Return the number of such valid permutations modulo 10^9 + 7.
*/
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class ValidPermutationsStream {
private static final int MOD = 1000000007;
public int numPermsDISequence(String s) {
int n = s.length();
int[][] dp = new int[n + 1][n + 1];
IntStream.range(0, n + 1).forEach(i -> dp[0][i] = 1);
IntStream.range(1, n + 1).forEach(i -> {
if (s.charAt(i - 1) == 'D') {
for (int j = i - 1; j >= 0; j--) {
dp[i][j] = (dp[i][j + 1] + dp[i - 1][j]) % MOD;
}
} else {
for (int j = 0; j < i; j++) {
dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % MOD;
}
}
});
return dp[n][0];
}
public static void main(String[] args) {
ValidPermutationsStream vp = new ValidPermutationsStream();
System.out.println(vp.numPermsDISequence("DID")); // Output: 5
System.out.println(vp.numPermsDISequence("D")); // Output: 1
}
}
解释
方法:
这个题解采用动态规划的方法。定义 f[i][j] 表示前 i 个字符构成的子序列中,以 j 结尾的有效排列数量。为了简化空间复杂度,使用一维数组 f[j] 不断更新来表示当前的状态,并用辅助数组 g[j] 来计算更新。对于每一个字符,根据是 'D' 还是 'I',决定填充的方向和方式。如果是 'D',从后向前更新 g[j],累积前面的 f[j] 值确保递减;如果是 'I',从前向后更新 g[j],累积前面的 f[j] 值以保证递增。最后,将 g 赋值回 f 进行下一轮的计算。计算结束后,f 数组的累加和就是所求的答案。
时间复杂度:
O(n^2)
空间复杂度:
O(n)
代码细节讲解
🦆
在动态规划的解法中,一维数组f的初始设置为[1] + [0] * n的原因是什么?
▷🦆
为什么在处理字符'D'和'I'时更新g数组的迭代方向不同?
▷🦆
在动态规划中,前缀和pre的作用具体是什么,它如何帮助计算g数组?
▷🦆
在遍历完成所有字符后,为何可以通过返回f数组的元素之和模10^9+7得到最终答案?
▷