变形字符串识别 Scramble String

本文介绍了一种判断两个字符串是否可以通过有限次交换子串得到对方的算法。该算法基于二叉树模型,通过递归检查所有可能的子串划分来验证两个字符串是否互为乱序形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题: 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.

思路:二叉树是可以任意生成的,长度为n的字符串可以有C(2n,n)/(n+1)种这样的二叉树(参见卡特兰数应用)。通过两个字符串反推出二叉树有难度。注意到,变形的次数不受限制,但是仅能够对调同一个结点的两个孩子。其规律是,对调完之后,不管其孩子内部是否还会对调,两个孩子子串仍然会是Anagram。

因此,从最外层开始尝试:第一层划分(也就是二叉树的第一次分叉)发生在什么位置;以及尝试:根节点的两个孩子有没有发生对调。递归着往里进行。

class Solution {
public:
    bool isScramble(string s1, string s2) {
        int m = s1.size();
        int n = s2.size();
        if(m != n)
            return false;
        return isValid(s1, s2);
        
    }
    bool isAnagram(string s1, string s2)
    {
        sort(s1.begin(), s1.end());
        sort(s2.begin(), s2.end());
        return (s1 == s2);
    }
    
    bool isValid(string s1, string s2)
    {
        if(s1 == s2)  //一样必正确
            return true;
        int n = s1.size();
        if(n == 1) //不可再划分
            return false;
        if(!isAnagram(s1, s2)) //非变形词必错误
            return false;
        
        for(int i = 0;i<n-1;i++) //尝试分叉位置
        {
            //左右对调型
            if(isValid(s1.substr(0, i+1), s2.substr(n-i-1)))
                if (isValid(s1.substr(i+1), s2.substr(0, n-i-1)))
                    return true;
            
            //左右没对调型
            if(isValid(s1.substr(0, i+1), s2.substr(0, i+1)))
                if (isValid(s1.substr(i+1), s2.substr(i+1)))
                    return true;
        }
        return false;
    }
};
PS:判断Anagram的方法有很多,这里使用的是排序法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值