[LeetCode] 1092. Shortest Common Supersequence 最短公共超序列



Given two strings str1 and str2, return the shortest string that has both str1 and str2 as subsequences.  If multiple answers exist, you may return any of them.

(A string S is a subsequence of string T if deleting some number of characters from T (possibly 0, and the characters are chosen anywhere from T) results in the string S.)

Example 1:

Input: str1 = "abac", str2 = "cab"
Output: "cabac"
Explanation:
str1 = "abac" is a subsequence of "cabac" because we can delete the first "c".
str2 = "cab" is a subsequence of "cabac" because we can delete the last "ac".
The answer provided is the shortest such string that satisfies these properties.

Note:

  1. 1 <= str1.length, str2.length <= 1000
  2. str1 and str2 consist of lowercase English letters.

這道題給了兩個字符串 str1 和 str2,讓找出包含這兩個字符串為子序列的最短字符串,即最短公共超序列。分析例子可以發現,之所以最終返回的字符串長度為5,是因為給定的兩個字符串中都含有子序列 ab,這樣的話就可以縮小總的長度了。看來 str1 和 str2 的最長公共子序列越長,說明可重疊的部分越長,則最終返回的公共超序列的長度越短,那么這道題就轉為了求最長公共子序列 Longest Common Subsequence 的問題,也就是之后的這道 Longest Common Subsequence,還好博主提前做過。是使用動態規划 Dynamic Programming 來做的,不過略有不同的是,這里需要知道 LCS 具體是什么,而不僅僅是長度。所以這里的 DP 數組就要定義為二維字符串數組,但是狀態轉移方程還是一樣的,若二者對應位置的字符相同,表示當前的 LCS 又增加了一位,所以可以用 dp[i-1][j-1] + str1[i-1] 來更新 dp[i][j]。否則若對應位置的字符不相同,由於是子序列,還可以錯位比較,可以分別從 str1 或者 str2 去掉一個當前字符,那么其 dp 值就是 dp[i-1][j] 和 dp[i][j-1],取二者中的長度較大值來更新 dp[i][j] 即可,最終的結果保存在了 dp[m][n] 中。知道了 LCS 的字符串,就要來生成最短公共超序列了,需要使用個雙指針,分別指向 str1 和 str2 的開頭,然后遍歷 LCS 中所有的字符,對於每個遍歷到的字符,用 while 循環將 str1 中從i位置到當前字符之間的所有字符加到 res 中,同理,用 while 循環將 str2 中從j位置到當前字符之間的所有字符加到 res 中。然后 res 加上當前字符,並且i和j再分別自增1。遍歷完 LCS 之后,有可能i和j還沒有到 str1 和 str2 的末尾,所以需要將剩余的子串再分別加到 res 中即可,參見代碼如下:


class Solution {
public:
    string shortestCommonSupersequence(string str1, string str2) {
        string res;
        int m = str1.size(), n = str2.size();
        vector<vector<string>> dp(m + 1, vector<string>(n + 1));
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (str1[i - 1] == str2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + str1[i - 1];
                } else {
                    dp[i][j] = dp[i - 1][j].size() > dp[i][j - 1].size() ? dp[i - 1][j] : dp[i][j - 1];
                }
            }
        }
        int i = 0, j = 0;
        for (char c : dp[m][n]) {
            while (i < m && str1[i] != c) res += str1[i++];
            while (j < n && str2[j] != c) res += str2[j++];
            res += c;
            ++i; ++j;
        }
        return res + str1.substr(i) + str2.substr(j);
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1092


類似題目:

Longest Common Subsequence


參考資料:

https://leetcode.com/problems/shortest-common-supersequence/

https://leetcode.com/problems/shortest-common-supersequence/discuss/312710/C%2B%2BPython-Find-the-LCS

https://leetcode.com/problems/shortest-common-supersequence/discuss/312702/Java-DP-Solution(Similiar-to-LCS)


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM