动态规划——Valid Permutations for DI Sequence

We are given S, a length n string of characters from the set {'D', 'I'}. (These letters stand for "decreasing" and "increasing".)

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', then P[i] > P[i+1], and;
  • If S[i] == 'I', then P[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 }

 







posted @ 2018-10-30 09:37  messi2017  阅读(379)  评论(0编辑  收藏  举报