题目描述
给出三个队列 s1,s2,s3 ,判断 s3 是否是由 s1 和 s2 交叉得来。 如:s1 为 aabcc , s2 为 dbbca。 当 s3 为 aadbbcbcac 时,返回 true(即将 s1 拆成三部分: aa,bc,c 分别插入 s2 对应位置) 否则返回 false。
- 输入
aabcc,dbbca,aadbbcbcac
- 输出
true
- 输入样例
aabcc,dbbca,aadbbcbcac
aabcc,dbbca,aadbbbaccc
a,b,ab
a,b,ba
a,b,ac
abc,bca,bcaabc
abc,bca,aabbcc
- 输出样例
true
false
true
true
false
true
false
解题思路
本题使用动态规划算法,**dp[i][j]**表示使用s1的前i个字符和s2的前j个字符组成s3的前i+j个字符的可能性。很显然,dp[0][0] = true;,动态数组初始化为:
for (int i = 1; i <= s1.length(); i++)
dp[i][0] = dp[i - 1][0] && (s1[i - 1] == s3[i - 1]);
for (int i = 1; i <= s2.length(); i++)
dp[0][i] = dp[0][i - 1] && (s2[i - 1] == s3[i - 1]);
递归公式为:
int k = i + j;
if (s1[i - 1] == s3[k - 1])
dp[i][j] = dp[i][j] || dp[i - 1][j];
if (s2[j - 1] == s3[k - 1])
dp[i][j] = dp[i][j] || dp[i][j - 1];
参考代码
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <string>
using namespace std;
bool isValid(string s1, string s2, string s3) {
if (s3.length() != s1.length() + s2.length())
return false;
//动态数组,表示s1的前i个字符和s2的前j个字符组成s3的前i+j个字符的可能
vector<vector<bool> > dp(s1.length() + 1, vector<bool>(s2.length() + 1, false));
dp[0][0] = true;
for (int i = 1; i <= s1.length(); i++)
dp[i][0] = dp[i - 1][0] && (s1[i - 1] == s3[i - 1]);
for (int i = 1; i <= s2.length(); i++)
dp[0][i] = dp[0][i - 1] && (s2[i - 1] == s3[i - 1]);
for (int i = 1; i <= s1.length(); i++) {
for (int j = 1; j <= s2.length(); j++) {
int k = i + j;
if (s1[i - 1] == s3[k - 1])
dp[i][j] = dp[i][j] || dp[i - 1][j];
if (s2[j - 1] == s3[k - 1])
dp[i][j] = dp[i][j] || dp[i][j - 1];
}
}
return dp[s1.length()][s2.length()];
}
int main() {
string s1, s2, s3, s;
while (cin >> s) {
s1 = s.substr(0, s.find(','));
s = s.substr(s.find(',') + 1);
s2 = s.substr(0, s.find(','));
s3 = s.substr(s.find(',') + 1);
if (isValid(s1, s2, s3))
cout << "true" << endl;
else
cout << "false" << endl;
}
return 0;
}