最小化給定字串中的分割槽以獲取另一個字串
在這個問題中,我們需要透過切片另一個字串來構造一個字串。我們可以使用最長公共子串來解決這個問題。我們可以在兩個字串之間找到最長公共子串,將 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) 用於儲存動態規劃結果。