We are given S
, a length n
string of characters from the set {'D', 'I'}
. (These letters stand for "decreasing" and "increasing".)
A valid permutation is a permutation P[0], P[1], ..., P[n]
of integers {0, 1, ..., n}
, such that for all i
:
- If
S[i] == 'D'
, thenP[i] > P[i+1]
, and; - If
S[i] == 'I'
, thenP[i] < P[i+1]
.
How many valid permutations are there? Since the answer may be large, return your answer modulo 10^9 + 7
.
Example 1:
Input: "DID"
Output: 5
Explanation:
The 5 valid permutations of (0, 1, 2, 3) are:
(1, 0, 3, 2)
(2, 0, 3, 1)
(2, 1, 3, 0)
(3, 0, 2, 1)
(3, 1, 2, 0)
这道题目出自LeetCode,可以采用动态规划方法来解决
这篇博客主要是对LeetCode给出的第一种时间复杂度为O(n^3)的动态规划解法进行解释,题目的大意不再具体解释,有点英文基础的查查百度也能知道
这个题说的是个什么意思。由于采用的是动态规划解法,所以要找出状态和状态转移方程。LeetCode给的那个解法里面把状态dp[i][j]确定为以下的含义:
我们每次只注重最后一个数字在整个数组序列中 小->大 排列后的位置,如果给数组编号为i = 0、1、...、n,我们关注的焦点dp[i][j]可以解释为长度为i+1的数组中某个方案中
其最后一个数字即第i个数字在这i+1个数字中处于第j+1小位置的方案的数量,比如dp[0][0]的意义就是长度为长度为1的数组{0}按字符串S的要求下重新排列后的新数组其第0个数字在整个数组中排最小的方案数字,而且易知dp[0][0]=1。
而且dp[0]只用dp[0][0]这一个元素,其他的用不上,对于每个i = 0、1、...、n,我们只用dp[i][0..i]这些元素。
状态转移方程的解释更加复杂,如果S[i-1]=='D',递减,则p[i]<p[i-1],这个时候dp[i][j]是所有dp[i-1][j<=k<=i-1]的和,k之所以小于i是因为对于dp[i-1]来说它一共就i个成员,下标访问到i会越界,k大等于j的原因不好解释,
有一个替换的问题在里面,因为dp[i]比dp[i-1]多一个元素,它们所代表的数组也是前者比后者多一个,由于dp[i]所属的数组方案中按 小->大的数组和dp[i-1]的那个数组中第k(1<=k<=i)个数字是一样的,这里我不知道怎么叙述好,
反正就是dp[i]所代表的那个长的最后一位可以使用dp[i-1]所代表的那个短的最后一位,因为是递减,可以把dp[i]代表的数组中多出来的那一个最大的数组顶在倒数第二个位置上;如果S[i-1]=='T',由于dp[i]所属的数组方案中按 小->大
的数组和dp[i-1]的那个数组中第k(1<=k<=i)个数字是一样的,dp[i][j]是所有dp[i-1][0<=k<j]的和。这个题的思路上确实是比较复杂的,也不是很好叙述清楚它的思路。这个题最后一个注意点就是要求模,记住每次求模即可。
下面直接上代码:
1 int numPermsDISequence(string S){ 2 int MOD = 1000000007; 3 int n = S.length(); 4 int**dp = new int*[n + 1]; 5 for (int i = 0; i <= n; i++) 6 dp[i] = new int[n + 1]; 7 for (int i = 0; i <= n;i++) 8 for (int j = 0; j <= n; j++){ 9 if (i == 0)dp[i][j] = 1; 10 else dp[i][j] = 0; 11 } 12 for (int i = 1; i <= n; i++){ 13 for (int j = 0; j <= i; j++){ 14 if (S[i - 1] == 'D'){ 15 for (int k = j; k < i; k++){ 16 dp[i][j] += dp[i - 1][k]; 17 dp[i][j] %= MOD; 18 } 19 } 20 else{ 21 for (int k = 0; k < j; k++){ 22 dp[i][j] += dp[i - 1][k]; 23 dp[i][j] %= MOD; 24 } 25 } 26 } 27 } 28 29 for (int i = 0; i <= n; i++){ 30 for (int j = 0; j <= n; j++) 31 cout << dp[i][j] << " "; 32 cout << endl; 33 } 34 35 36 int ans = 0; 37 for (int i = 0; i <= n; i++){ 38 ans += dp[n][i]; 39 ans %= MOD; 40 } 41 for (int i = 0; i <= n; i++) 42 delete[]dp[i]; 43 delete[]dp; 44 return ans; 45 }