• 动态规划——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 }
    
    
    






  • 相关阅读:
    K-Means++ 聚类之数据可视化:使用gnuplot
    QQ设计第1-5步
    QQ设计第1-5步
    为什么有很深的windows基础还是不能动摇linux半步
    常用命令
    在线会计_金蝶友商网
    XP使用VNC远程桌面CentOS 6
    Fatal error: Call to undefined function mb_substr()
    如何汉化 po 文件及编译成 mo 文件
    idoerp
  • 原文地址:https://www.cnblogs.com/messi2017/p/9874956.html
Copyright © 2020-2023  润新知