2021-04-24

使用下面描述的算法可以扰乱字符串 s 得到字符串 t :如果字符串的长度为 1 ,算法停止
                                                                                      如果字符串的长度 > 1 ,执行下述步骤:
                        在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
                        随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
                        在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。
                        给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。

样例:s1=great ,s2=rgeat;返回:true;

思路:首先,我们先看样例,great先经过gr/eat被分割为两个字符串,然后gr交换位置得到rgeat。在great被分割为gr和eat两部分时,最终的rgeat其实也被分成两部分,gr对应rg,eat对应eat。由此我们可以把rgeat是否是great的扰乱字符串转化为求rg是否是gr的扰乱字符串并且eat是否是eat的扰乱字符串。如果两个条件同时存在,我们就可以确定great和rgeat是扰乱字符串。

方法1:暴力法:

public class Main{
    public static void main(String[] args){
        String s1="great";
        String s2="rgeat";
        System.out.println(check(s1,s2));

    }
    public static boolean check(String s1,String s2){
        if(s1.equals(s2))return true;
        if(!check1(s1,s2))return false;
        for(int i=1;i<s1.length();i++){
            String a=s1.substring(0,i);
            String b=s1.substring(i);
            String c=s2.substring(0,i);
            String d=s2.substring(i);
            if(check(a,c)&&check(b,d))return true;
            String e=s2.substring(s1.length()-i);
            String f=s2.substring(0,s1.length()-i);
            if(check(a,e)&&check(b,f))return true;
        }
        return false;
        
    }
    public static boolean check1(String a,String b){
        if(a.length()!=b.length())return false;
        int[] arr=new int[26];
        int[] array=new int[26];
        for(int i=0;i<a.length();i++){
            arr[a.charAt(i)-'a']++;
            array[b.charAt(i)-'a']++;
        }
        for(int i=0;i<26;i++){
            if(arr[i]!=array[i])return false;
        }
        return true;
        
    }
}

方法二:记忆化递归

在上面的代码中,我们可以发现会多次执行重复操作,所以我们可以定义一个数组,表示已经执行过的操作,我们在递归时会优先查看这个数组,当发现已经执行过的操作我们直接返回,否则继续操作。

我们用一个三维数组存储已经执行的操作,如果已经执行并且返回值为true时,存储1,如果已经执行返回为false,存储-1.未执行存储0

class Main{
    static int Y=1;
    static int N=-1;
    static int[][][] dp;
    static String s1,s2;
    public static void main(String[] args){
        s1="great";
        s2="rgeat";
        if(s1.equals(s2))return true;
        if(!check(s1,s2))return false;
        int n=s1.length();
        dp=new int[n][n][n+1];//len表示长度,范围在1-n之间
        dfs(0,0,n);
    }
    public static boolean dfs(int i,int j,int len){//len表示长度,
        if(dp[i][j][len]!=0)return dp[i][j][len]==1;
        String a=s1.substring(i,i+len);
        String b=s1.substring(j,j+len);
        if(a.equals(b)){
            dp[i][j][len]=Y;
            return true;
        }
        if(!check(a,b)){
            dp[i][j][len]=N;
            return false;
        }
        for(int k=1;k<len;k++){
            if(dfs(i,j,k)&&dfs(i+k,j+k,len-i)){
                dp[i][j][len]=Y;
                return true;
            }
            if(dfs(i,j+len-k,k)&&dfs(i+k,j,len-k)){
                dp[i][j][len]=Y;
                return true;
            }
        }
        dp[i][j][len]=N;
        return false;
    }
    public static boolean check(String s1,String s2){
        if(s1.length()!=s2.length())return false;
        int n=s1.length();
        int[] arr=new int[26];
        int[] array=new int[26];
        for(int i=0;i<n;i++){
            arr[s1.charAt(i)-'a']++;
            array[s2.charAt(i)-'a']++;
        }
        for(int i=0;i<26;i++){
            if(arr[i]!=array[i])return false;
        }
        return true;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值