• Java实现 LeetCode 87 扰乱字符串


    87. 扰乱字符串

    给定一个字符串 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

    PS:两种方法dfs执行效率高一点(其实dp的效率应该更高,但小编能力有限了)

    class Solution {
          public boolean isScramble(String s1, String s2) {
            if (s1.length()==0 && s2.length()==0) return true;
            if (s1.length()!=s2.length()) return false;
            return dfs(s1.toCharArray(), s2.toCharArray(), 0, 0, s1.length());
        }
        private boolean dfs(char[] s1, char[] s2, int start1, int start2, int len){
            if (len==1) {
                return s1[start1]==s2[start2];
            }
            if (!equals(s1, s2, start1, start2, len)) {
                return false;
            }
            for (int i=1; i<len; i++){
    
                //两个字符串是否相等                    我的搜索位置往后走i,我的结束就要往前走i防止超限
                if (dfs(s1, s2, start1, start2, i) && dfs(s1, s2, start1+i, start2+i, len-i)) return true;
            //  |i到len-1|这块进行翻转
                if (dfs(s1, s2, start1, start2+len-i, i) && dfs(s1, s2, start1+i, start2, len-i)) return true;
            }
            return false;
        }
        public boolean equals(char[] s1, char[] s2, int start1, int start2, int len){
            int[] charArr = new int[26];
            for (int i=0; i<len; i++) {
                charArr[s1[start1+i] - 'a']++;
                charArr[s2[start2+i] - 'a']--;
            }
            for (int item : charArr) {
                if (item != 0) return false;
            }
            return true;
        }
    }
    
    class Solution {
        public boolean isScramble(String s1, String s2) {
             if(s1==null&&s2!=null||s2==null&&s1!=null||s1.length()!=s2.length()) return false;
        boolean[][][] dp=new boolean[s1.length()][s2.length()][s1.length()+1];
        //初始化len=1
        for (int i = 0; i < s1.length(); i++) {//第一个字符串的起点
            for (int j = 0; j < s2.length(); j++) {//第二个字符串的起点
                if(s1.charAt(i)==s2.charAt(j)) dp[i][j][1]=true;
            }
        }
        for (int len = 2; len <=s1.length(); len++) {//区间长度
            for (int i = 0; i < s1.length(); i++) {//第一个字符串的起点,终点i+len-1
                for (int j = 0; j < s2.length(); j++) {//第二个字符串的起点,终点j+len-1
                    for (int k = 1; k <len; k++) {//左边区间的长度,因为要划分成两个区间,所以左边那个区间的长度是1...len-1(至少为一,至多也得给第二个区间留一个)
                        if(i+k<s1.length()&&j+k<s1.length()&&j+len-k<s1.length()&&((dp[i][j][k]&&dp[i+k][j+k][len-k])||(dp[i][j+len-k][k]&&dp[i+k][j][len-k]))){
                            dp[i][j][len]=true;
                            break;
                        }
                    }
                }
            }
        }
        return dp[0][0][s1.length()];
        }
    }
    

    PS:

    //dp[i][j][k][l] 表示s1的i-j和s2的k-l是否互为扰乱字符串,因为j-i=l-k,所以优化成 //dp[i][j][k] 表示s1的i...i+k和s2的j...j+k是否互为扰乱字符串
    

    这里有大佬的各种实现方式

  • 相关阅读:
    [C++] Const Summary (mind map)
    [C++] Operator Overload
    [C++] Deep copy ,Shallow copy, copy constructor,"="
    [C++] CONST 2
    [C++] * Basic and Class
    《Javascript权威指南-第6版》
    Bootstrap源码分析系列之初始化和依赖项
    Bootstrap源码分析系列之整体架构
    CSS模糊效果
    韩顺平php从入门到精通
  • 原文地址:https://www.cnblogs.com/a1439775520/p/12946825.html
Copyright © 2020-2023  润新知