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
程序中为了方便起见只进行了前一部分的字符直方统计,后一部分没有进行(程序依然可以在后面的过程中对相应部分进行检验,正确性可以保证)
还可以将直方统计用的数组作为类的成员从而减少栈空间的使用