【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];

    }

}; 

 

你可能感兴趣的:(LeetCode)