最小化给定字符串中的分区以获取另一个字符串


在这个问题中,我们需要通过切片另一个字符串来构造一个字符串。我们可以使用最长公共子串来解决这个问题。我们可以在两个字符串之间找到最长公共子串,将 str1 切分成 1 或 2 部分,并从 str2 中删除子串。再次,我们在更新的字符串中找到最长公共子串并继续执行,直到 str2 变成空。通过这种方式,我们可以解决问题。

问题陈述 – 我们给定了 str1 和 str2 两个长度不同的字符串。我们需要通过切片和连接 str1 的部分来构造字符串 str2。我们需要找到使用 str1 获取 str2 字符串所需的最小切片次数。如果无法构造 str2 字符串,则打印“-1”。

示例

输入

str1 = "tutorialspoint"; str2 = "intpotu";

输出

3

解释 – 如图所示,我们需要将 str1 切分成 4 部分,共 3 次。

Tu | torials | po | int

输入

str1 = "tutorialspoint"; str2 = "intpotu";

输出

-1

解释 – 由于我们无法从 str1 构造 str2。所以,它打印“-1”。

输入

str1 = "Welcome"; str2 = "meWe";

输出

2

解释 – We | lco | me

方法 1

在这种方法中,我们将找到给定字符串之间的最长公共子串,切分字符串,并从两个字符串中删除子串。此外,我们将在每次迭代中更新这两个字符串,并进行迭代,直到 str2 字符串变为空。

此外,我们需要关注切分起始和结束部分,因为在这种情况下我们只需要 1 次切分。此外,如果字符已在子串中计算,我们将 str1 的字符更新为“0”。

算法

步骤 1 – 如果 str1 的大小小于 str2,则返回 -1,因为无法从 str1 构造 str2。如果两个字符串相同,则返回 0。

步骤 2 – 将“answer”初始化为 0 以存储 str1 的总切片次数。

步骤 3 – 使用 while 循环进行迭代,直到 str2 的大小大于零。

步骤 4 – 执行 longCommonSubStr() 函数以获取 str1 和 str2 中的最长公共子串。

步骤 4.1 – 在 longCommonSubStr() 函数中,将“maxLen”变量初始化为 0 以存储最大长度,“endingStr1”和“endingStr2”初始化为 0 以存储 str1 和 str2 中子串的结束索引。另外,初始化“mat”以存储以前的结果,因为我们使用动态规划方法来查找最长公共子串,并用 0 初始化“currentRow”。

步骤 4.2 – 开始填充二维矩阵。

步骤 4.3 – 如果 p 和 q 为 0,则在 mat[currentRow][q] 中存储零。

步骤 4.4 – 如果 str1 中索引 (p-1) 处的字符和 str2 中索引 (q – 1) 处的字符相同,则通过添加到先前的对角线条目来更新 mat[currentRow][q] 的值。

步骤 4.5 – 如果更新后的值大于 maxLen 变量的值,则更新“maxLen”、“endingStr1”和“endingStr2”变量的值。

步骤 4.6 – 否则,将 mat[currentRow][q] = 0 分配为 0,因为我们需要开始一个新的子串。

步骤 4.7 – 当嵌套循环的迭代完成时,更新“currentRow”变量的值。

步骤 4.8 – 创建“temp”数组以存储最长公共子串长度,以及 str1 和 str2 中的结束索引。最后,返回“temp”数组。

步骤 5 – 在 getMinSlices() 函数中,如果最长公共子串的长度为 0,则返回 -1。

步骤 6 - 如果子串的起始索引为 0,则如果 str1 中子串最近的下一个字符不为“0”,则将“answer”值加 1。如果结束索引等于“len – 1”,则如果子串之前的字符不为“0”,则将“answer”值加 1。如果为“0”,则该部分已切分,因此我们不需要增加“answer”的值。

步骤 7 – 如果我们需要从中间切分字符串,则如果子串之前和之后的字符不等于“0”,则相应地增加“answer”的值。

步骤 8 – 使用 substr() 方法从 str2 中删除公共子串。

步骤 9 – 通过执行 replaceSubStr() 函数更新 str1 字符串,该函数将所有子串字符替换为“0”。

步骤 9.1 – 在 replaceSubStr() 函数中,使用 substr() 方法从字符串中获取初始子串。之后,创建一个包含与子串长度相等的总零的中字符串,并获取结束子串。

步骤 9.2 – 连接初始、中间和结束字符串后返回字符串。

步骤 10 – 返回“answer”值。

示例

#include <bits/stdc++.h>
using namespace std;
int *longCommonSubStr(string str1, string str2) {
    // String sizes
    int len1 = str1.size();
    int len2 = str2.size();
    // To store the maximum length of the common substring.
    int maxLen = 0;
    // For storing the ending index of the substring.
    int endingStr1 = 0;
    int endingStr2 = 0;
    // 2D array to store max len of consecutive rows
    int mat[2][len1 + 1];
    // Pointer to the row
    int currentRow = 0;
    // Finding the longest common substring
    for (int p = 0; p <= len1; p++) {
        for (int q = 0; q <= len2; q++) {
            if (p == 0 || q == 0) {
                mat[currentRow][q] = 0;
            } else if (str1[p - 1] == str2[q - 1]) {
                mat[currentRow][q] = mat[1 - currentRow][q - 1] + 1;
                // If we get longer substring, update values.
                if (mat[currentRow][q] > maxLen) {
                    maxLen = mat[currentRow][q];
                    endingStr1 = p - 1;
                    endingStr2 = q - 1;
                }
            } else {
                mat[currentRow][q] = 0;
            }
        }
        // Change the current row
        currentRow = 1 - currentRow;
    }
    // Storing the starting index of longest common substring
    int *temp = new int[3];
    temp[0] = (endingStr1 - maxLen + 1);
    temp[1] = (endingStr2 - maxLen + 1);
    temp[2] = maxLen;
    return temp;
}
string replaceSubStr(string str1, int ind, int sub_len) {
    // Get initial string
    string start = str1.substr(0, ind);
    string mid = "";
    // Create string with all 0's
    for (int p = 0; p < sub_len; p++) {
        mid += "0";
    }
    // Get remaining string
    string end = str1.substr(ind + sub_len);
    // Return final string
    return (start + mid + end);
}
int getMinSlices(string str1, string str2) {
    // Return -1 if length of str2 is greater
    if (str1.size() < str2.size())
        return -1;
    // Handle the case when both strings are equal.
    if (str1 == str2)
        return 0;
    int answer = 0, len1 = (str1.size() - 1);
    // Find longest common substring of str1 and str2, until str2 is empty.
    while (str2.size() > 0) {
       int *lcs = longCommonSubStr(str1, str2);
        // If the length of the substring is 0, return -1
        if (lcs[2] == 0)
            return -1;

        // Handling the case when starting point is 0, or the ending point is len1
        if ((lcs[0] + lcs[2] - 1 == len1) || lcs[0] == 0) {
            // If the startind index is 0, and the last character is not '0', we need to slice. Otherwise, it's already sliced.
            if (lcs[0] == 0) {
                if (str1[lcs[0] + lcs[2]] != '0')
                    answer++;
            } else {
                // If the ending index is len1, the previous character of the substring's first character is '0', last part of the string is already sliced.
                if (str1[lcs[0] - 1] != '0')
                    answer++;
            }
        }
        // When the substring is between the last and ending character
        else {
            // Increment answer value if strings are not sliced already.
            if (str1[lcs[0] + lcs[2]] != '0') {
                answer++;
            } 
            if (str1[lcs[0] - 1] != '0') {
                answer++;
            }
        }
        // Remove lcs from str2.
        str2 = str2.substr(0, lcs[1]) + str2.substr(lcs[1] + lcs[2]);
        // Pleace '0' in str1 at the place of lcs
        str1 = replaceSubStr(str1, lcs[0], lcs[2]);
    }
    // final output
    return answer;
}
int main() {
    string str1 = "tutorialspoint";
    string str2 = "intpotu";
    cout << "The minimum slices of string str1 is required to construct a string str2 is " << getMinSlices(str1, str2) << endl;
}

输出

The minimum slices of string str1 is required to construct a string str2 is 3

时间复杂度 – O(N*M*M),因为 O(N*M) 用于查找最长公共子串,O(M) 用于减少 str2。

空间复杂度 – O(N),其中 O(N) 用于存储动态规划结果。

更新于: 2023年8月25日

85 次查看

启动你的 职业生涯

通过完成课程获得认证

开始
广告