【leetcode】 Scramble String (hard)★
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
Below is one possible representation of s1 = "great"
:
great / \ gr eat / \ / \ g r e at / \ a t
To scramble the string, we may choose any non-leaf node and swap its two children.
For example, if we choose the node "gr"
and swap its two children, it produces a scrambled string "rgeat"
.
rgeat / \ rg eat / \ / \ r g e at / \ a t
We say that "rgeat"
is a scrambled string of "great"
.
Similarly, if we continue to swap the children of nodes "eat"
and "at"
, it produces a scrambled string "rgtae"
.
rgtae / \ rg tae / \ / \ r g ta e / \ t a
We say that "rgtae"
is a scrambled string of "great"
.
Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
判断两个字符串s1和s2是否可以通过旋转实现。
思路:开始傻眼了,反应不过来。第二天恍然大悟,用递归,分左右部分,变成子问题。但是最开始我以为划分树只有一种方式,后来发现树可以随意的划分,左子树可以有任意个字符,右子树也是。所以需要循环遍历所有条件。再然后是可能s1的左半部分在s2中位于左半部分 或者是右半部分,所以对这两种情况也要都考虑到。
循环的时候用了截枝,如果两边的字符有不一致的直接跳过该次循环。
#include <iostream> #include <vector> #include <algorithm> #include <queue> #include <stack> #include <string> using namespace std; class Solution { public: bool isScramble(string s1, string s2) { if(s1.length() != s2.length()) return false; if(s1 == s2) return true; if(!isEqual(s1 , s2)) { return false; } for(int i = 1; i < s1.length(); i++) { int leftlength = i; int rightlength = s1.length() - leftlength; string s1left1 = s1.substr(0, leftlength); string s2left1 = s2.substr(0, leftlength); string s1right1 = s1.substr(leftlength, rightlength); string s2right1 = s2.substr(leftlength, rightlength); string s1left2 = s1.substr(rightlength, leftlength); string s1right2 = s1.substr(0, rightlength); if(!isEqual(s1left1,s2left1) && !isEqual(s1left2,s2left1)) { continue; } if((isScramble(s1left1, s2left1) && isScramble(s1right1, s2right1)) || (isScramble(s1left2, s2left1) && isScramble(s1right2, s2right1))) { return true; } } return false; } //判断两个字符串的字母组成是否一致 bool isEqual(string s1, string s2) { if(s1.length() != s2.length()) return false; for(int i = 0; i < s1.length(); i++) { int locate = s2.find(s1[i]); if(locate == string::npos) { return false; } else { s2.erase(s2.begin() + locate); } } return true; } }; int main() { Solution s; string s1 = "oatzzffqpnwcxhejzjsnpmkmzngneo"; string s2 = "acegneonzmkmpnsjzjhxwnpqffzzto"; //string s1 = "gneo"; //string s2 = "gneo"; bool ans = s.isScramble(s1, s2); return 0; }
有大神给出了正宗动态规划的解法,非常精简,要好好学习。 不过这个方法算了所有的情况所以时间比我的要长,差不多150ms, 我的是50ms左右。
dp[i][j][l] means whether s2.substr(j,l) is a scrambled string of s1.substr(i,l) or not.
class Solution { public: bool isScramble(string s1, string s2) { int len=s1.size(); bool dp[100][100][100]={false}; for (int i=len-1;i>=0;i--) for (int j=len-1;j>=0;j--) { dp[i][j][1]=(s1[i]==s2[j]); for (int l=2;i+l<=len && j+l<=len;l++) { for (int n=1;n<l;n++) { //所有划分左右区间的情况 dp[i][j][l]|=dp[i][j][n]&&dp[i+n][j+n][l-n]; //s1的左边对s2的左边 dp[i][j][l]|=dp[i][j+l-n][n]&&dp[i+n][j][l-n];//s1的左边对s2的右边 } } } return dp[0][0][len]; } };