Leetcode 87 扰乱字符串

104 阅读2分钟

给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。

下图是字符串 s1 = "great" 的一种可能的表示形式。


    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t

在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。

例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。

    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t

我们将 "rgeat” 称作 "great" 的一个扰乱字符串。

同样地,如果我们继续交换节点 "eat" 和 "at" 的子节点,将会产生另一个新的扰乱字符串 "rgtae" 。

    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a

我们将 "rgtae” 称作 "great" 的一个扰乱字符串。

给出两个长度相等的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。

示例 1:

输入: s1 = "great", s2 = "rgeat" 输出: true

示例 2:

输入: s1 = "abcde", s2 = "caebd" 输出: false

题解
1 主要是使用递归,但是如果单纯使用递归则可能出现tle,这里利用异或来排除肯定不可能是搅乱字符串的字符串

/**
 * @param {string} s1
 * @param {string} s2
 * @return {boolean}
 */

function isScramble(s1, s2) {
  if (s1.length != s2.length) return false;
  if (s1 == s2) return true;
  if (s1.length == 0 || s2.length == 0) return true;
  let s1Arr = new Array(26).fill(0);
  let s2Arr = new Array(26).fill(0);

  // 统计s1中出现a-z的个数,统计s2中a-z出现的个数,然后对比,假设如果出现a的次数不相等,则可以直接返回false

  for (let i = 0; i < s1.length; i++) {
    s1Arr[s1.charCodeAt(i) - 97]++;
    s2Arr[s2.charCodeAt(i) - 97]++;
  }
  for (let i = 0; i < 26; i++) {
    if (s1Arr[i] !== s2Arr[i]) {
      return false;
    }
  }

  // 递归寻找是否是是相对搅乱的字符串
  const len = s1.length;
  // 前面是否相同,通过异或来判断,比如1^1 = 0
  let sameBegin = 0;
  let sameLast = 0;
  for (let i = 0, j = len - 1; i < len; i++, j--) {
    // 如果前面是可能是搅乱的, 比如[1,2,3] 和 [3,2,1] , 1^3^2^2^3^1 = 0
    sameBegin ^= s1.charCodeAt(i) ^ s2.charCodeAt(i);
    // 如果后面可能是搅乱的
    sameLast ^= s1.charCodeAt(i) ^ s2.charCodeAt(j);

    if (sameBegin === 0 && i < len - 1) {
      if (
        isScramble(s1.substring(0, i + 1), s2.substring(0, i + 1)) &&
        isScramble(s1.substring(i + 1, len), s2.substring(i + 1, len))
      ) {
        return true;
      }
    }

    if (sameLast == 0 && i < len - 1) {
      if (
        isScramble(s1.substring(0, i + 1), s2.substring(len - i - 1)) &&
        isScramble(s1.substring(i + 1), s2.substring(0, len - i - 1))
      ) {
        return true;
      }
    }
  }
  return false;
}

export default isScramble;