首页 > 代码库 > LeetCode Scramble String

LeetCode Scramble String

class Solution {
public:
    bool isScramble(string s1, string s2) {
        int len = s1.length();
        if (len == 1 && s1[0] == s2[0]) return true;
        
        int a_st_front[256] = {0};
        int b_st_back[256]  = {0};
        // int a_st_back[256]  = {0};
        int b_st_front[256] = {0};
        
        for (int i=0; i<len-1; i++) {
            a_st_front[ s1[i] ]++;
            b_st_back[ s2[len - i - 1] ]++;
            
            if ( is_alphabeta_stat_equal(a_st_front, b_st_back, 256) ) {
                if ( isScramble(s1.substr(0, i + 1), s2.substr(len - i - 1, i+1))
                    && isScramble(s1.substr(i + 1, len - i - 1), s2.substr(0, len - i - 1)) ) {
                        return true;
                }
            }
            
            b_st_front[ s2[i] ]++;

            if ( is_alphabeta_stat_equal(b_st_front, a_st_front, 256) ) {
                if ( isScramble( s1.substr(0, i + 1), s2.substr(0, i + 1) )
                    && isScramble(s1.substr(i + 1, len - i - 1), s2.substr(i + 1, len - i - 1)) ) {
                        return true;
                }
            }
        }
        return false;
    }

    bool is_alphabeta_stat_equal(int* a, int *b, int len) {
        for (int i=0; i<len; i++) {
            if (a[i] != b[i]) return false;
        }
        return true;
    }
};

dfs二分遍历,采用字符直方统计进行一些裁剪。比如题目例子中的字符串:rgtae 和 great

当最顶层substring其中一个长度为一时的可能情况:

r | gtae <----> g | reat (最上层substring为旋转)

r | gtae <----> grea | t (最上层substring已旋转)

不管旋转与否,两个对应的字符,在一个字符区段内的字符直方统计总是相同的,如果不同必然不会是Scramble,此时我们就可以排除这个分支。

当枚举到substring为2时

rg | tae <---> gr | eat

rg | tae <---> gre | at

可以发现子串rg的字符直方统计和gr是一致的,tae和eat是一致的所以这种划分是一种可能,如果rg和gr是scramble 且 tae和eat也是scramble则整两个字符串scramble

程序中为了方便起见只进行了前一部分的字符直方统计,后一部分没有进行(程序依然可以在后面的过程中对相应部分进行检验,正确性可以保证)

还可以将直方统计用的数组作为类的成员从而减少栈空间的使用