zoukankan      html  css  js  c++  java
  • 【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];
        }
    }; 
  • 相关阅读:
    ZABBIX实现原理及架构详解
    for(;;)和while(true)的区别
    JVM
    javap的基本用法
    Java VisualVM添加Visual GC插件
    Java虚拟机监控命令
    数据类型 原始类型的方法
    数据类型 数字类型
    Object(对象):基础知识 原型对象prototype
    Object(对象):基础知识 对象方法,"this"
  • 原文地址:https://www.cnblogs.com/dplearning/p/4169016.html
Copyright © 2011-2022 走看看