交叉字串問題、判斷字串s3是不是由字串s1和s2交叉組合而成
阿新 • • 發佈:2018-12-24
前言
題目:交叉字串問題,給出三個字串s1,s2,s3,判斷s3是否可以由s1和s2兩個字串經過交叉組合而成,組合過程不能改變字元在s1,s2字串中的原本順序。例:
s1=”aabcc”
s2=”dbbca”
s3=”aadbbcbcac”或者s3=”aadbbbaccc”
給了兩種s3的情況,第一種情況下答案是yes,第二種情況下答案是no,因為找不到任何一種s1和s2的交叉組合方式可以組合成s3。
解法思想
剛拿到這個題的時候,其實是不知道怎麼做的。想想應該用動態規劃,但其實一時也想不到怎麼動規,找了些題解後,發現大多隻有程式碼,很少具體分析,正好很久沒做動規的題,乾脆自己畫個表格,寫篇部落格鞏固一下。
大概思想如下:
1. 動態規劃求解,構造一個長為,寬為 的 二維陣列;
2. 設有,其中表示字串 的第 個字元, 表示字串 的第 個字元, 表示 的第 個字元;
3. 如果為 ,表示 等於 且 等於 、 或者 等於 且 ;
4. 簡單的說 為 就表示這個點可達,以 為起點, 為終點,dp陣列中值為 的點為路徑,向下走表示取 的字元,向右走表示取 的字元。這樣就將抽象的字元組合轉化成了更好理解的二維陣列來表示;
5. 最優子結構即為: 的 點字元之前的字元能否交叉組合成字串 的前 個字元,轉換到二維陣列即為, 點左側點和上方的點是否可達。
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;
}