使用下面描述的算法可以扰乱字符串 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;
}
}