• Leetcode 87.扰乱字符串


    扰乱字符串

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

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

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

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

     

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

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

     

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

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

    示例 1:

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

    输出: true

    示例 2:

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

    输出: false

    【分析】

    题意在于判断一个字符串是否为另一个字符串"乱序"得到,这种乱序采用的方式是将一个字符串从某个位置"割开",形成两个子串,然后对两个子串进行同样的"割开"操作,直到到达叶子节点,无法再分割。然后对非叶子节点的左右孩子节点进行交换,最后重新从左至右组合形成新的字符串,由于这个过程中存在字符位置的变化,因此,原来的字符串顺序可能会被打乱,当然也可能没有(同一个非叶子节点的左右孩子交换0次或偶数次,就无变化)。需要注意的点:

    1、原字符串每次被割开的位置并不确定可能为[1,s.size()-1],所以必然需要遍历所有可能割开的位置;

    2、原字符串从第i个位置被割开(i在区间[1,s.size()-1]),形成的两个子串s.substr(0,i)和s.substr(i,s.size()-i),如果这两个子串不全为空,则它们的母串(这里指原字符串)就是所谓的非叶子节点,这两个子串可以左右交换(按照二叉树的展开方式);对于两个子串,可继续割裂,直到形成叶子节点。

    3、可以想见,原字符串对应的"乱序"串s1,定然满足如下规律:如果将"乱序"串同样从第i个位置割开,他同样可以形成两个子串,s1.substr(0,i)和s1.substr(i,s1.size()-i),并且满足:

    s1.substr(0,i)是s.substr(0,i)的"乱序"且s1.substr(i,s1.size()-i)是s.substr(i,s.size()-i)的""乱序

    或者(因为左右交换的原因)

    s1.substr(0,i)是s.substr(s.size()-i)的"乱序"且s1.substr(i)是s.substr(0,s.size()-i)的"乱序"

    4、如上分析,我们就可以将大问题分解成小问题,通过递归调用,便可以判断两个字符串是否互为"乱序",还需注意一个问题就是"剪枝"操作,二叉树形式分解,层次很深,每一层都应满足(3)中的两种可能之一,如果不满足便不再继续下一层,直接返回false,这便是一种剪枝操作,可以极大的提升效率。

    5、"剪枝"约束,若两个字符串s1和s2互为"乱序",需满足s1和s2包含的字符及数量应完全相同,如果不同,则不可能构成"乱序",因此这个条件可作为剪枝条件;

    6、两个工具:判断两个字符串是否包含完全相同的字母,用到了"哈希表";割裂形成子串用到STL函数:substr(i,n);表示获得字符串从第i个位置开始的n个字符,如果n空缺,默认为到字符串末尾。

     1 class Solution{
     2     public:
     3     bool isScramble(string s1,string s2){
     4         if(s1.size()!=s2.size()) return false;
     5         if(s1==s2) return true;
     6         vector<int> hash(26,0);
     7         for(int i=0;i<s1.size();i++)
     8             hash.at(s1[i]-'a')++;
     9         for(int j=0;j<s2.size();j++)
    10             hash.at(s2[j]-'a')--;
    11         for(int k=0;k<26;k++){
    12             if(hash.at(k)!=0)
    13                 return false;
    14         }
    15         for(int i=1;i<s1.size();i++){
    16             if((isScramble(s1.substr(0,i),s2.substr(0,i))&&isScramble(s1.substr(i,s1.size()-i),s2.substr(i,s1.size()-i)))
    17                     ||(isScramble(s1.substr(0,i),s2.substr(s1.size()-i))&& isScramble(s1.substr(i),s2.substr(0,s1.size()-i))))
    18                 return true;
    19         }
    20         return false;
    21     }
    22 };
  • 相关阅读:
    20201227《信息安全专业导论》第八周学习总结
    20201227任峰皓《信息安全导论》第七周学习总结
    20201227任峰皓《信息安全导论》第六周学习总结
    斐波那契数列递归实现
    求最大公约数伪代码
    20201227 获奖感言与学习心得
    20201227任峰皓《信息安全导论》第五周学习总结
    xor加密
    pep9作业
    20201227任峰皓《信息安全导论》第四周学习总结
  • 原文地址:https://www.cnblogs.com/kexinxin/p/10163067.html
Copyright © 2020-2023  润新知