Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc"
,
s2 = "dbbca"
,
When s3 = "aadbbcbcac"
, return true.
When s3 = "aadbbbaccc"
, return false.
算法一,递归
假定s1[i]和s2[j]之前的字符,和s3[i+j+1]之前的字符,已经满足interleave条件,则添加新字符是否能组成新的interleave的条件为:
若 s1[i] == s3[i+j+1] 或者 s2[j] == s3[i+j+1]
但是简单递归,时间是却无法被AC。如下面的这样的case:
s1 = "bbbbbabbbbabaababaaaabbababbaaabbabbaaabaaaaababbbababbbbbabbbbababbabaabababbbaabababababbbaaababaa",
s2 = "babaaaabbababbbabbbbaabaabbaabbbbaabaaabaababaaaabaaabbaaabaaaabaabaabbbbbbbbbbbabaaabbababbabbabaab",
s3 ="babbbabbbaaabbababbbbababaabbabaabaaabbbbabbbaaabbbaaaaabbbbaabbaaabababbaaaaaabababbababaababbababbbababbbbaaaabaabbabbaaaaabbabbaaaabbbaabaaabaababaababbaaabbbbbabbbbaabbabaabbbbabaaabbababbabbabbab"
class Solution { public: bool isInterleave(string s1, string s2, string s3) { return helper(s1.data(), s2.data(), s3.data()); } bool helper(const char *s1, const char *s2, const char *s3) { if (!*s3) return !*s1 && !*s2; return *s1 == *s3 && helper(s1+1, s2, s3+1) || *s2 == *s3 && helper(s1, s2+1, s3+1); } };
算法二:
dp[i][j]表示, s1的[0,i]子串,s2的[0,j]的子串,是否能满足s3的[0, i+j+1]子串的interleave关系。
要求出dp[i][j],需要 dp[i-1][j] 和 dp[i][j-1]两个历史信息。
即: dp[i][j] = dp[i-1][j] && s1[i] == s3[i+j+1] || dp[i][j-1] && s2[j] == s3[i+j+1];
需要一个二维的数组做辅助空间。
但是,由于所需的历史信息,其实是当前的列的前一行,以及当前的行的前一列。 即正上和正左。
这样的情况,可以用滚动数组,去代替二维数组。
即,只需要保留上一行的信息,以及前一列的信息。
故只需要一维数组就行了。 为进一步进省内存,可以选择较短字符的长度作为辅助空间。
class Solution { public: bool isInterleave(string s1, string s2, string s3) { if (s1.size() + s2.size() != s3.size()) return false; if (s2.size() > s1.size()) s2.swap(s1); vector<char> dp(s2.size()+1); dp[0] = 1; for (int j=0; j<s2.size(); j++) dp[j+1] = dp[j] && s2[j] == s3[j]; for (int i=0; i<s1.size(); i++) { dp[0] = dp[0] && s1[i] == s3[i]; for (int j=0; j<s2.size(); j++) { dp[j+1] = dp[j] && s2[j] == s3[i+j+1] || dp[j+1] && s1[i] == s3[i+j+1]; } } return dp[s2.size()]; } };