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)
Note:
1 <= S.length <= 200
S
consists only of characters from the set{'D', 'I'}
.
题目理解:
给定一个长度为n的字符串,仅由‘D’和‘I’组成,求符合要求的数组的数量,符合要求的数组是由0,1,2,...,n组成的数组,并且在出现‘D’的对应位置递减,在出现‘I’的对应位置递增
解题思路:
动态规划。举例:符合“DI”的数组只有1,0,2和2,0,1,要求符合“DID”的数组,我们需要在前面的两个数组中添加数字,如果我们添加num,那么就把数组中所有>=num的数字+1,这样,我们就可以把num添加到数组的最后,并且使得原数组仍然符合“DI”规则,可以看出来,如果是i位置是‘D’,那么我们可以添加所有小于等于最后一个数字的num,如果是‘I’,我们可以添加所有大于最后一个数字的num,所以我们总结地推公式如下:
dp[i][j]代表符合DI规则的前i个位置的由j结尾的数组的数目,那么可以求得递推公式:
dp[i][j] = 取和dp[i-1][k] 其中k>=j DI字符串在i位置是‘D’
dp[i][j] = 取和dp[i-1][k] 其中k<j DI字符串在i位置是‘I’
由地推公式可以看出我们需要的是dp[i][0],dp[i][1],...,dp[i][j]的和,因此我们改变dp[i][j]的意义,dp[i][j]此时代表前述的和,做到这一点只需要在代码中添加dp[i][j]+=dp[i][j-1]
代码如下:
class Solution {
public int numPermsDISequence(String S) {
int len = S.length();
char[] chs = S.toCharArray();
int[][] record = new int[len + 1][len + 1];
record[0][0] = 1;
int base = 1000000007;
for(int i = 1; i < len + 1; i++) {
char ch = chs[i - 1];
for(int j = 0; j <= i; j++) {
if(ch == 'D') {
record[i][j] += record[i - 1][i - 1];
if(j != 0)
record[i][j] -= record[i - 1][j - 1];
}
else if(ch == 'I') {
if(j != 0)
record[i][j] += record[i - 1][j - 1];
}
record[i][j] %= base;
if(j > 0)
record[i][j] += record[i][j - 1];
record[i][j] %= base;
}
if(i < len)
record[i][i + 1] = record[i][i];
}
return (record[len][len] + base) % base;
}
}