zoukankan      html  css  js  c++  java
  • [LeetCode] Scramble String

    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.

    Hide Tags
     Dynamic Programming String
     
     
    思路一: 递归,首先想到的是递归(即深搜),对两个 string 进行分割,然后比较四对字符串。代码虽然简单,但是复杂度比较高。有两种加速策略,一种是剪枝,提前返回;一种是加缓存,缓存中间结果,即

    memorization(翻译为记忆化搜索)。 这个版面没有任何剪纸和缓存,所以超时了 Time Limit Exceeded

    class Solution {
        public:
            bool isScramble(string s1, string s2) {
                //cout << "s1	" << s1 << endl;
                //cout << "s2	" << s2 << endl;
                if(s1.size() != s2.size())
                    return false;
                if(s1 == s2)
                    return true;
                int s1Size = s1.size();
                int s2Size = s2.size();
                int s1aSize;
                int s1bSize;
    
                for(s1aSize = 1;s1aSize < s1Size ; s1aSize++ )
                {
                    s1bSize =  s1Size - s1aSize;
                    //cout << "s1aSize	" << s1aSize << endl;
                    //cout << "s1bSize	" << s1bSize << endl;
    
                    if( (isScramble(s1.substr(0,s1aSize), s2.substr(0,s1aSize)) &&
                         isScramble(s1.substr(s1aSize, s1bSize), s2.substr(s1aSize, s1bSize)))
                         || (isScramble(s1.substr(0,s1aSize), s2.substr(s1bSize,s1aSize)) &&
                             isScramble(s1.substr(s1aSize, s1bSize), s2.substr(0, s1bSize))) )
                            return true;
                }
                return false;
            }
    };

     思路二,在递归的基础上进行剪枝,判断两个字符串是否互为 scamble,至少要求每个字符在两个字符串中出现的次数要相等,如果不相等则返回 false。

    成功AC

    class Solution { 
        public: 
            bool isScramble(string s1, string s2) { 
                //cout << "s1	" << s1 << endl; 
                //cout << "s2	" << s2 << endl; 
                if(s1.size() != s2.size()) 
                    return false; 
                if(s1 == s2) 
                    return true; 
                int s1Size = s1.size(); 
                int s2Size = s2.size(); 
                int s1aSize; 
                int s1bSize; 
     
                      
                int cnt[256]; 
                fill(cnt, cnt+ 256, 0); 
     
                for(int i = 0; i < s1Size; i++)
                {
                    cnt[s1[i]]  ++;
                }
                for(int i = 0; i < s2Size; i++)
                {
                    cnt[s2[i]] --;
                }
                for(int i = 0; i < 256; i++)
                {
                   if(cnt[i] != 0) 
                        return false;
                }
    
    
                for(s1aSize = 1;s1aSize < s1Size ; s1aSize++ )
                {
                    s1bSize =  s1Size - s1aSize;
                    //cout << "s1aSize	" << s1aSize << endl;
                    //cout << "s1bSize	" << s1bSize << endl;
    
                    if( (isScramble(s1.substr(0,s1aSize), s2.substr(0,s1aSize)) &&
                         isScramble(s1.substr(s1aSize, s1bSize), s2.substr(s1aSize, s1bSize))) 
                         || (isScramble(s1.substr(0,s1aSize), s2.substr(s1bSize,s1aSize)) &&
                             isScramble(s1.substr(s1aSize, s1bSize), s2.substr(0, s1bSize))) )
                            return true;
                }
                return false;
            }
    };

     思路三:备忘录法,其实就是递归+ 缓存(cache),也成功AC

    class Solution {
            map<string, bool>  cache;
        public:
            bool isScramble(string s1, string s2) {
                cache.clear();
                return isScrambleInternal(s1, s2);
            }
    
            bool isScrambleInternal(string s1, string s2) {
                //cout << "s1	" << s1 << endl;
                //cout << "s2	" << s2 << endl;
                if(s1.size() != s2.size())
                    return false;
                if(s1 == s2)
                    return true;
                int s1Size = s1.size();
                int s2Size = s2.size();
                int s1aSize;
                int s1bSize;
    
                for(s1aSize = 1;s1aSize < s1Size ; s1aSize++ )
                {
                    s1bSize =  s1Size - s1aSize;
    
                    if( (getOrUpdate(s1.substr(0,s1aSize), s2.substr(0,s1aSize)) &&
                                getOrUpdate(s1.substr(s1aSize, s1bSize), s2.substr(s1aSize, s1bSize))) 
                            || (getOrUpdate(s1.substr(0,s1aSize), s2.substr(s1bSize,s1aSize)) &&
                                getOrUpdate(s1.substr(s1aSize, s1bSize), s2.substr(0, s1bSize))) )
                    {   
                        return true;
                    }   
                }   
                return false;
            }   
    
            bool getOrUpdate(string str1, string str2)
            {
                string str = str1 + str2;
                if(cache.count(str))
                    return cache[str];
    
                bool res = isScrambleInternal(str1, str2);
                cache[str1+str2] = res;
                cache[str2+str1] = res;
                //cout << "str1	" << str1<< endl;
                //cout << "str2	" << str2<< endl;
                //cout << "res	" << res<< endl;
                return res;
            }
    };

     思路四:dp ,

    既然可以用记忆化搜索,这题也一定可以用动规。设状态为 f[n][i][j],表示长度为 n,起
    点为 s1[i] 和起点为 s2[j] 两个字符串是否互为 scramble,则状态转移方程为
    f[n][i][j]} = (f[k][i][j] && f[n-k][i+k][j+k])
    || (f[k][i][j+n-k] && f[n-k][i+k][j])

    class Solution {
        public:
            bool isScramble(string s1, string s2) {
                const int N = s1.size();
                if (N != s2.size()) return false;
            // f[n][i][j],表示长度为 n,起点为 s1[i] 和
            // 起点为 s2[j] 两个字符串是否互为 scramble
                bool f[N + 1][N][N];
          //fill_n(f, (N+1)*N*N, false); // this is wrong fill_n(
    &f[0][0][0], (N + 1) * N * N, false); for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) f[1][i][j] = s1[i] == s2[j]; for (int n = 1; n <= N; ++n) { for (int i = 0; i + n <= N; ++i) { for (int j = 0; j + n <= N; ++j) { for (int k = 1; k < n; ++k) { if ((f[k][i][j] && f[n - k][i + k][j + k]) || (f[k][i][j + n - k] && f[n - k][i + k][j])) { f[n][i][j] = true; break; } } } } } return f[N][0][0]; } };
  • 相关阅读:
    Activex打包于发布完整版---ActiveX打包
    同步和异步的区别
    QoS的构建模块与机制
    GLSL语言内置的变量详解
    jquery中的DOM操作
    varchar和Nvarchar区别
    使用SqlServer中的float类型时发现的问题
    SQL2005,错误 0xc00470fe 数据流任务 产品级别对于 组件“源
    SQL SERVER SQLOS的任务调度
    隐式事务(转)
  • 原文地址:https://www.cnblogs.com/diegodu/p/4362817.html
Copyright © 2011-2022 走看看