LeetCode OJ 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.

挺难的一道题,刚开始做的时候以为建树的规则是二分,结果才发现是随机的划分建树。

应该如何做呢?

我们先来看简单的情况,如果说划分是确定的,是每次都平均分成两份,如果字符数是单数则前半份比后半份少一。

比如题目中的“great”就是极好的例子。

由于已知划分点,我们可以知道原来字符串的建树:

LeetCode OJ Scramble String - Night - Time Ends.

 假设需要检查的字符串是X1X2X3X4X5,那么,由于知道是对半划分,可知:

①要么:gr对应X1X2,同时eat对应X3X4X5;

②要么:gr对应X4X5,同时eat对应X1X2X3;比如此时X1X2X3X4X5为eatgr。

对于gr,同理:

如果是①,那么将gr对半划分,可知:

①①要么:g对应X1,同时r对应X2;

①②要么:r对应X1,同时g对应X2;比如:rgeat。

剩下步骤同理。

综上,如果可知建树的规则是对半平分,那么我们只需深搜一下,对两个字符串不断地平分,匹配,直到发现匹配或者深搜完了都没有匹配。

但是,这里的规则并不是平分。

那么只需要在深搜中将当前字符串依次划分就好了,比如先划成X1, X2X3X4X5试试,然后是X1X2, X3X4X5,接着X1X2X3, X4X5……

对于每一次深搜,如果当前两个划分的字符串(各来自题目给的两个string)刚好相等,说明当前划分是匹配的,返回true(但是还没有匹配完,还有两个string剩下的部分);

如果当前的两个字符串无法一一对应(也就是分别排序后还不相等),那么当前划分不匹配。

class Solution {
public:
    int * letters;
    string S1, S2;
    bool isScramble(string s1, string s2) {
        if (s1.size() != s2.size()) return false;
        letters = new int[60];
        S1 = s1, S2 = s2;
        return dfs(0, S1.size(), 0, S2.size());
    }
    bool dfs(int l1, int r1, int l2, int r2) {  // 这里用四个下标来指代当前两个字符串

        if (S1.substr(l1, r1 - l1) == S2.substr(l2, r2 - l2)) return true;  // 如果当前两个字符串相等了

        for (int i = 0; i < 52; i++) letters[i] = 0;  // 检查两个当前字符串的字母类型和个数是否一样
        for (int i = l1; i < r1; i++) 
            if ('A' <= S1[i] && S1[i] <= 'Z') letters[S1[i] - 'A']++;
            else letters[S1[i] - 71]++;
        for (int i = l2; i < r2; i++)
            if ('A' <= S2[i] && S2[i] <= 'Z') letters[S2[i] - 'A']--;
            else letters[S2[i] - 71]--;
        for (int i = 0; i < 52; i++) if (letters[i]) return false;

        for (int i = 1; i < r1 - l1; i++) {
            if ((dfs(l1, l1 + i, l2, l2 + i) && dfs(l1 + i, r1, l2 + i, r2))) return true;  // 如果gr和X1X2匹配且eat和X3X4X5匹配
            if ((dfs(l1, l1 + i, r2 - i, r2) && dfs(l1 + i, r1, l2, r2 - i))) return true;  // 如果gr和X4X5匹配且eat和X1X2X3匹配
        }

        return false;

    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值