给定2个字符串,判断是否能够通过重排列这2个字符串而产生另外一个字符串
RT,给定字符串s1,s2判断能否通过重排列 s1 s2从而产生s3.注意s1 s2中字符的相对顺序不能变。
如:
s1 = abc
s2 = def
s3 = abcdef return true
s3 = adefbc return true
s3 = aefdbc return false
思路:
1.递归,很简单的思路,代码如下:
bool Can(string s1, string s2, string s3) { if (s3.size() != s1.size() + s2.size()) return false; if (s1.size() == 0 && s2 == s3 ) return true; if (s2.size() == 0 && s1 == s3) return true; if (s1[0] == s3[0]) { if(isInterleave(s1.substr(1, s1.size() - 1),s2, s3.substr(1, s3.size() - 1))) return true; } if (s2[0] == s3[0]) { if(isInterleave(s1,s2.substr(1, s2.size() - 1), s3.substr(1, s3.size() - 1))) return true; } return false; }
递归的思路类似穷举,分析一下复杂度?在没有大量重复字符的时候,递归的复杂度其实还可以,但如果有大量重复字符,这个时间复杂度就难以接受了,有木有更简单的?
2.动态规划,我的理解,递归是一种不保存历史记录的动态规划,如果我们将现场保存,那么递归很容易转化为动态规划。
bool can(string s1, string s2, string s3) { if (s3.size() != s1.size() + s2.size()) return false; if (s1.size() == 0) { if (s2 == s3) return true; else return false; } if (s2.size() == 0 ) { if (s1 == s3) return true; else return false; } vector<vector<bool> > dp; dp.resize(s1.size() + 1); for (int i = 0; i <= s1.size(); ++i) { dp[i].resize(s2.size() + 1, false); for (int j = 0; j <= s2.size(); ++j) { if (i == 0 && j == 0) dp[i][j] = true; else if (i == 0) { if (s3[i + j - 1] == s2[j - 1] && dp[i][j - 1]) dp[i][j] = true; } else if (j == 0) { if (s3[i + j - 1] == s1[i - 1] && dp[i - 1][j]) dp[i][j] = true; } else { if (s3[i + j - 1] == s2[j - 1] && dp[i][j - 1]) dp[i][j] = true; if (s3[i + j - 1] == s1[i - 1] && dp[i - 1][j]) dp[i][j] = true; } } } return dp[s1.size()][s2.size()]; }
代码其实写得很罗嗦,基本思想是用一张表记录历史状态,没加入一个新的元素,就可以获取历史计算结果进行参考。空间复杂度为O(N^2)
其实可以进一步缩小空间复杂度的。