字符串Y 和 Z 之间给定字符串X 的子序列计数
给定三个字符串,' X ',' Y '和' Z ',任务是计算' X '的子序列的数量,这些子序列在字典上大于或等于' Y '并且在字典上小于或等于' Z ' .
例子:
Input: X = “abc”, Y = “a”, Z = “bc”
Output: 6
Explanation: The subsequences of X which are greater than or equal to string ‘Y’ and lesser than or equal to string ‘Z’ are
{ “a”, “b”, “ab”, “ac”, “bc”, “abc” }
Input: X = “ade”, Y = “a”, Z = “dc”
Output: 5
Explanation: The subsequences of X which are greater than or equal to string ‘Y’ and lesser than or equal to string ‘Z’ are
{ “a”, “d”, “ad”, “ae”, “ade”}
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 。
- 如果bound1为false ,则子序列大于字符串'Y',因此返回1 。
- 如果idx2 < Ysize ,则子序列等于字符串'Y' 直到idx2 – 1 ,但不完全相等,因此返回0 。
- 如果已经计算了状态dp[idx1][idx2][bound1][bound2]的结果,则返回此值dp[idx1][idx2][bound1][bound2] 。
- 如果当前元素从子序列中排除,递归调用函数countOfSubsequence为idx1 + 1 。
- 为了在子序列中包含字符串' X '的idx1处的当前元素,我们必须检查字符串' Y '和' Z '中的约束,
- 对于字符串' Y ',
- 如果bound1为false ,则可以包含当前元素,因为子序列已经大于字符串“ Y ”。
- 否则,如果idx2 >= Ysize ,则可以包含当前元素,因为子序列已经等于字符串“ Y ”,并且正在向其中添加更多字符。
- 否则,如果X[idx1] >= Y[idx2] ,通过包含当前元素,当前子序列在字典上大于或等于字符串“ Y ”,因此可以包含在内。
- 如果满足上述三个条件中的任何一个,则可以将当前元素包含在字符串' Y '中。
- 如果bound1为true ,请检查X[idx1] == Y[idx2] 。如果X[idx1] > Y[idx2] ,将bound1更新为false 。
- 对于字符串' Z ',
- 如果bound2为false ,则可以包含当前元素,因为子序列已经小于字符串' Z '。
- 否则,如果idx2 < Zsize和X[idx1] <= Z[idx2] ,通过包含当前元素,当前子序列在字典上小于或等于字符串“ Z ”,因此可以包含在内。
- 如果满足上述两个条件中的任何一个,则可以将当前元素包含在字符串“ Z ”中。
- 如果bound2为true ,请检查X[idx1] == Z[idx2] 。如果X[idx1] < Z[idx2] ,将bound1更新为false 。
- 将当前元素放在idx1后,递归调用countOfSubsequence函数(idx1 + 1, idx2 + 1) 。
- 对于字符串' Y ',
- 如果idx1 = Xsize的值,
- 打印函数countOfSubsequence(0, 0, 1, 1)返回的值作为结果。
插图:
X = “ac”
Y = “ab”
Z = “bc”
count(0, 0, 1, 1)
/ (Exclude) \ Can be included (X[0] == Y[0], X[0] < Z[0])
/ \ bound1 = 1, bound2 = 0 (as X[0] < Z[0] )
count(1, 0, 1, 1) count(1, 1, 1, 0)
/ (Exclude) \ Cannot be included / (Exclude) \ Can be included (X[1] > Y[1], X[1] == Z[1])
/ \ X[1] > Y[0] / \ bound1 = 0 (as X[1] > Y[1])
/ \ but X[1] > Z[0] / \ bound2 = 0 (as it was previously also 0)
Returns ‘0’ [“”] Returns ‘0’ [“c”] Returns ‘0’ [“a”] Returns ‘1’ [“ac”]
empty subsequence [bound1 = 1, [bound1 = 0]
[idx2 == 0] but idx2 < Y.size()]
Hence the final answer is 1, i.e., “ac”.
下面是上述方法的实现:
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)