leetcode | 87. 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.

Example 1:

Input: s1 = "great", s2 = "rgeat"
Output: true

Example 2:

Input: s1 = "abcde", s2 = "caebd"
Output: false

思路与解法

这道题目让我们判断是否存在从s1转化为s2的一种可行方法。题目保证输入数据满足s1、s2长度相等。
乍一看,感觉是将s1所有组成字符进行重新排列组合然后将获得的字符串与s2作比较。但是实际上这道题目加了隐藏的“限制”。因为Example 2abcde不能转化为caebd
下面,简单解释一下,为什么abcde不能转化为caebd:由题目可知,我们可以将s1分为两个字串,然后这两个字串可以交换顺序,也可以不交换从而生成新的s1;同样,我们可以对两个字串进行相同的操作。
由此可知,我们从s1进行转化所能得到的字符串是有限的,必须是由上述操作得到的。这是一个十分明显的递归结构,所以我们可以采用递归的方法来判断s1是否可以转化为s2。
如果s1可以转化为s2,那么一定满足以下两个条件之一:

扫描二维码关注公众号,回复: 4121137 查看本文章
  • 不交换子串:s1和s2的前i个字符分别组成的子串可以相互转化,并且s1和s2的后len(s1)-i个字符分别组成的子串可以相互转化;
  • 交换子串:s1的前i个字符组成的子串和s2后i个字符组成的子串可以相互转化,并且s1的后len(s1)-i个字符组成的子串和s2后len(s2)-i个字符组成的可以相互转化。
if isScramble(s1[0:i],s2[0:i]) && isScramble(s1[i:], s2[i:])
	return true

if isScramble(s1[:i], s2[len(s2)-i:]) && isScramble(s1[i:], s2[:len(s2)-i])
	return true

代码实现

此算法我使用go语言实现:

func isScramble(s1 string, s2 string) bool {
    // 如果s1==s2直接返回true
    if s1 == s2 {
        return true
    }
    // 判断s1和s2中是否存在不相同的字符,避免后续递归的消耗
    s1Slice := strings.Split(s1, "")
    s2Slice := strings.Split(s2, "")
    sort.Strings(s1Slice)
    sort.Strings(s2Slice)
    if strings.Join(s1Slice, "") != strings.Join(s2Slice, "") {
        return false
    }
    // 递归过程,对应于分析过程中的两种情况
    for i:=1; i<len(s1);i++ {
        if (isScramble(s1[:i], s2[:i]) && isScramble(s1[i:], s2[i:])) || (isScramble(s1[:i], s2[len(s2)-i:]) && isScramble(s1[i:], s2[:len(s2)-i])) {
            return true
        }
    }
    return false
}

遇到的问题

最初并没有判断s1和s2中是否存在不相同的字符,结果造成了无用的递归,消耗了大量的时间,造成了超时:
在这里插入图片描述
加入判断之后程序才可以通过,不过排序的时间复杂度为 O ( N l o g N ) O(NlogN) ,所以我们采用下面 O ( N ) O(N) 复杂度的判断方法:

alphabet := make([]int,26)
for i:=0;i<len(s1);i++ {
    alphabet[s1[i]-'a']+=1
    alphabet[s2[i]-'a']-=1
}
for i:=0;i<26;i++ {
    if alphabet[i] != 0 {return false}
}
return true

猜你喜欢

转载自blog.csdn.net/liuyh73/article/details/83716260