1. 程式人生 > >交叉字串問題、判斷字串s3是不是由字串s1和s2交叉組合而成

交叉字串問題、判斷字串s3是不是由字串s1和s2交叉組合而成

前言

題目:交叉字串問題,給出三個字串s1,s2,s3,判斷s3是否可以由s1和s2兩個字串經過交叉組合而成,組合過程不能改變字元在s1,s2字串中的原本順序。例:
s1=”aabcc”
s2=”dbbca”
s3=”aadbbcbcac”或者s3=”aadbbbaccc”
給了兩種s3的情況,第一種情況下答案是yes,第二種情況下答案是no,因為找不到任何一種s1和s2的交叉組合方式可以組合成s3。

解法思想

剛拿到這個題的時候,其實是不知道怎麼做的。想想應該用動態規劃,但其實一時也想不到怎麼動規,找了些題解後,發現大多隻有程式碼,很少具體分析,正好很久沒做動規的題,乾脆自己畫個表格,寫篇部落格鞏固一下。

大概思想如下:
1. 動態規劃求解,構造一個長為len2=s2.size()+1,寬為len1=s1.size()+1dp[][] 二維陣列;
2. 設有ij,其中i表示字串s1 的第i 個字元,j 表示字串s2 的第j 個字元,t=i+j 表示s3 的第t 個字元;
3.dp[i][j] 如果為1 ,表示s1[i] 等於s3[t]dp[i1][j] 等於1 、 或者s2[j] 等於

s3[t]dp[i][j1]
4. 簡單的說dp[i][j]1 就表示這個點可達,以dp[0][0] 為起點,dp[len1][len2] 為終點,dp陣列中值為1 的點為路徑,向下走表示取s1 的字元,向右走表示取s2 的字元。這樣就將抽象的字元組合轉化成了更好理解的二維陣列來表示;
5. 最優子結構即為:s1,s2i,j 點字元之前的字元能否交叉組合成字串s3 的前i+j 個字元,轉換到二維陣列即為,i,j 點左側點和上方的點是否可達。
6. 可以根據例1畫出二維表格,便於分析:

s1/s2 * d b b c a
* 1 0 0 0 0 0
a 1 0 0 0 0 0
a 1 1 1 1 1 0
b 0 1 1 0 1 0
c 0 1 1 1 1 1
c 0 0 0 1 0 1

注:通過畫出表格可以更容易的理解動態規劃的過程,同時也會發現,這個方法不僅可以找出是否能進行交叉組合,還能找到有種交叉組合的辦法。下邊貼出C++程式碼。

/*交叉字串*/

#include <iostream>
#include <vector>
#include <string>

using namespace std;

bool isInterleave(string s1, string s2, string s3) {
    int len1 = s1.size();
    int len2 = s2.size();
    int len3 = s3.size();
    if (len3 != len1 + len2)
        return false;
    if (len1 == 0)
        return s2 == s3;
    if (len2 == 0)
        return s1 == s3;
    vector<vector<int> > dp(len1 + 1, vector<int>(len2 + 1));
    dp[0][0] = 1;
    //init dp array
    for (int i = 1; i < len1 + 1; i++) {
        if (s1[i - 1] == s3[i - 1])
            dp[i][0] = dp[i - 1][0];
    }
    for (int i = 1; i < len2 + 1; i++) {
        if (s2[i - 1] == s3[i - 1])
            dp[0][i] = dp[0][i - 1];
    }
    //dp
    for (int i = 1; i < len1 + 1; i++) {
        for (int j = 1; j < len2 + 1; j++) {
            int t = i + j;
            if (s1[i - 1] == s3[t - 1]) {
                dp[i][j] = dp[i - 1][j] || dp[i][j];
            }
            if (s2[j - 1] == s3[t - 1]) {
                dp[i][j] = dp[i][j - 1] || dp[i][j];
            }
        }
    }
    if (dp[len1][len2] == 1)
        return true;
    return false;
}

int main() {
    string s1 = "aabcc";
    string s2 = "dbbca";
    string s3 = "aadbbcbcac";
    if (isInterleave(s1, s2, s3))
        cout << "yes" << endl;
    else
        cout << "no" << endl;
    return 0;
}