📌  相关文章
📜  字符串Y 和 Z 之间给定字符串X 的子序列计数

📅  最后修改于: 2022-05-13 01:56:04.375000             🧑  作者: Mango

字符串Y 和 Z 之间给定字符串X 的子序列计数

给定三个字符串,' X ',' Y '和' Z ',任务是计算' X '的子序列的数量,这些子序列在字典上大于或等于' Y '并且在字典上小于或等于' Z ' .

例子:

Naive Approach:最简单的方法是生成字符串' X '的所有子序列,并检查它是否大于或等于' Y '并且小于或等于' Z '。

时间复杂度: O(2 N * N)
辅助空间: O(N)

高效方法:上述方法也可以通过使用动态规划进行优化,因为它具有重叠的子问题和最优的子结构。子问题可以使用 memoization 存储在dp[][][][]表中,其中dp[idx1][idx2][bound1][bound2]存储从字符串' X ' 的第 idx1位置到结尾以及从字符串' Y ' 和 ' Z ' 的第 idx2位置直到结束,其中bound1是一个布尔变量,它告诉在idx1之前构造的子序列是否等于 ' Y ' 直到idx2的相应子字符串,并且bound2是一个布尔变量,它告诉直到idx1构造的子序列是否等于 ' Z ' 直到idx2的相应子串。

请按照以下步骤解决问题:

  • 初始化一个全局多维数组dp[100][100][2][2] ,所有值都为-1 ,存储每个递归调用的结果。
  • 通过执行以下步骤定义一个递归函数,例如countOfSubsequence(idx1, idx2, bound1, bound2)
    • 如果idx1 = Xsize的值,
      • 如果idx2 = 0 ,则子序列为空,因此返回0
      • 如果bound1false ,则子序列大于字符串'Y',因此返回1
      • 如果idx2 < Ysize ,则子序列等于字符串'Y' 直到idx2 – 1 ,但不完全相等,因此返回0
    • 如果已经计算了状态dp[idx1][idx2][bound1][bound2]的结果,则返回此值dp[idx1][idx2][bound1][bound2]
    • 如果当前元素从子序列中排除,递归调用函数countOfSubsequenceidx1 + 1
    • 为了在子序列中包含字符串' X '的idx1处的当前元素,我们必须检查字符串' Y '和' Z '中的约束,
      • 对于字符串' Y ',
        • 如果bound1false ,则可以包含当前元素,因为子序列已经大于字符串“ Y ”。
        • 否则,如果idx2 >= Ysize ,则可以包含当前元素,因为子序列已经等于字符串“ Y ”,并且正在向其中添加更多字符。
        • 否则,如果X[idx1] >= Y[idx2] ,通过包含当前元素,当前子序列在字典上大于或等于字符串“ Y ”,因此可以包含在内。
        • 如果满足上述三个条件中的任何一个,则可以将当前元素包含在字符串' Y '中。
        • 如果bound1true ,请检查X[idx1] == Y[idx2] 。如果X[idx1] > Y[idx2] ,将bound1更新为false
      • 对于字符串' Z ',
        • 如果bound2false ,则可以包含当前元素,因为子序列已经小于字符串' Z '。
        • 否则,如果idx2 < ZsizeX[idx1] <= Z[idx2] ,通过包含当前元素,当前子序列在字典上小于或等于字符串“ Z ”,因此可以包含在内。
        • 如果满足上述两个条件中的任何一个,则可以将当前元素包含在字符串“ Z ”中。
        • 如果bound2true ,请检查X[idx1] == Z[idx2] 。如果X[idx1] < Z[idx2] ,将bound1更新为false
      • 将当前元素放在idx1后,递归调用countOfSubsequence函数(idx1 + 1, idx2 + 1)
  • 打印函数countOfSubsequence(0, 0, 1, 1)返回的值作为结果。

插图:

下面是上述方法的实现:

C++
// C++ program for the above approach:
 
#include 
using namespace std;
 
int dp[100][100][2][2];
 
string X, Y, Z;
int XSize, YSize, ZSize;
 
// Function to find the count
// of subsequences of 'X' which
// is greater than or equal to 'Y'
// but lesser than or equal to 'Z'.
int countOfSubsequence(
    int idx1, int idx2,
    bool bound1, bool bound2)
{
 
    // If the string 'X'
    // is traversed completely.
    if (idx1 == XSize) {
 
        // If subsequence is empty, return 0.
        if (idx2 == 0)
            return 0;
 
        // If bound1 is false (current subsequence
        // is larger than 'Y') or
        // idx2 is greater than or
        // equal to Ysize, return 1.
        if (!bound1 or idx2 >= YSize)
            return 1;
 
        // Else return 0.
        return 0;
    }
 
    // If the state has already
    // been computed, return it.
    if (dp[idx1][idx2][bound1][bound2] != -1) {
        return dp[idx1][idx2][bound1][bound2];
    }
 
    // Exclude the current element
    // from the subseqeunce.
    int ans = countOfSubsequence(
        idx1 + 1, idx2,
        bound1, bound2);
 
    // Variable to check if current
    // character can be included
    // the subsequence by checking
    // the strings 'Y' and 'Z'.
    int isOk = 0;
 
    // Check for first string
    // If bound1 is false,
    // it means the current character
    // can be included in the
    // subsequence as the current
    // subsequence is already
    // greater than the string 'Y'.
    if (!bound1) {
        ++isOk;
    }
 
    // If idx2 >= Ysize,
    // the subsequence formed by placing
    // current character is of greater length
    // than string 'Y', hence can be placed.
    // If current character is greater than
    // or equal to the corresponding
    // character in string 'Y', it can be placed.
    else if (idx2 >= YSize or X[idx1] >= Y[idx2]) {
        ++isOk;
        bound1 &= (idx2 < YSize
                   and X[idx1] == Y[idx2]);
    }
 
    // Check for second string
    // If bound2 is false,
    // it means the current character
    // can be included in the subsequence
    // as the current subsequence is already
    // lesser than the string 'Z'.
    if (!bound2) {
        ++isOk;
    }
 
    // If current character is lesser than
    // or equal to the corresponding character
    // in string 'Z', it can be placed.
    else if (idx2 < ZSize
             and X[idx1] <= Z[idx2]) {
        ++isOk;
        bound2 &= (X[idx1] == Z[idx2]);
    }
 
    // If constraints are met by both string
    // 'Y' and 'Z', it is possible to include
    // the current character of
    // string 'X' in the subsequence.
    if (isOk == 2) {
 
        // Increase both idx1 and idx2 by 1.
        ans += countOfSubsequence(
            idx1 + 1, idx2 + 1,
            bound1, bound2);
    }
 
    // Return the answer.
    return dp[idx1][idx2][bound1][bound2] = ans;
}
 
// Utility function to find the count
// of subsequences of 'X' which is
// greater than or equal to 'Y'
// but lesser than or equal to 'Z'.
int UtilCountOfSubsequence()
{
 
    // Initialize the dp array with -1.
    memset(dp, -1, sizeof dp);
 
    // Calculate the size of strings
    //'X', 'Y', and 'Z'.
    XSize = X.size();
    YSize = Y.size();
    ZSize = Z.size();
 
    // Function call
    return countOfSubsequence(0, 0, 1, 1);
}
 
// Driver code
int main()
{
    // Input strings 'X', 'Y' and 'Z'.
    X = "abc";
    Y = "a";
    Z = "bc";
 
    // If string 'Y' is greater
    // than string 'Z', return 0.
    if (Y > Z) {
        cout << 0 << endl;
        return 0;
    }
 
    cout << UtilCountOfSubsequence()
         << endl;
}


Javascript


输出
6

时间复杂度: O(N 2 * 2 * 2)
辅助空间: O(N 2 * 2 * 2)