|
|
package class13;
|
|
|
|
|
|
// 本题测试链接 : https://leetcode.com/problems/scramble-string/
|
|
|
public class Code03_ScrambleString {
|
|
|
|
|
|
public static boolean isScramble0(String s1, String s2) {
|
|
|
if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (s1 == null && s2 == null) {
|
|
|
return true;
|
|
|
}
|
|
|
if (s1.equals(s2)) {
|
|
|
return true;
|
|
|
}
|
|
|
char[] str1 = s1.toCharArray();
|
|
|
char[] str2 = s2.toCharArray();
|
|
|
if (!sameTypeSameNumber(str1, str2)) {
|
|
|
return false;
|
|
|
}
|
|
|
return process0(str1, 0, str1.length - 1, str2, 0, str2.length - 1);
|
|
|
}
|
|
|
|
|
|
// str1[L1...R1] str2[L2...R2] 是否互为玄变串
|
|
|
// 一定保证这两段是等长的!
|
|
|
public static boolean process0(char[] str1, int L1, int R1, char[] str2, int L2, int R2) {
|
|
|
if (L1 == R1) {
|
|
|
return str1[L1] == str2[L2];
|
|
|
}
|
|
|
for (int leftEnd = L1; leftEnd < R1; leftEnd++) {
|
|
|
boolean p1 = process0(str1, L1, leftEnd, str2, L2, L2 + leftEnd - L1)
|
|
|
&& process0(str1, leftEnd + 1, R1, str2, L2 + leftEnd - L1 + 1, R2);
|
|
|
boolean p2 = process0(str1, L1, leftEnd, str2, R2 - (leftEnd - L1), R2)
|
|
|
&& process0(str1, leftEnd + 1, R1, str2, L2, R2 - (leftEnd - L1) - 1);
|
|
|
if (p1 || p2) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
public static boolean sameTypeSameNumber(char[] str1, char[] str2) {
|
|
|
if (str1.length != str2.length) {
|
|
|
return false;
|
|
|
}
|
|
|
int[] map = new int[256];
|
|
|
for (int i = 0; i < str1.length; i++) {
|
|
|
map[str1[i]]++;
|
|
|
}
|
|
|
for (int i = 0; i < str2.length; i++) {
|
|
|
if (--map[str2[i]] < 0) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
public static boolean isScramble1(String s1, String s2) {
|
|
|
if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (s1 == null && s2 == null) {
|
|
|
return true;
|
|
|
}
|
|
|
if (s1.equals(s2)) {
|
|
|
return true;
|
|
|
}
|
|
|
char[] str1 = s1.toCharArray();
|
|
|
char[] str2 = s2.toCharArray();
|
|
|
if (!sameTypeSameNumber(str1, str2)) {
|
|
|
return false;
|
|
|
}
|
|
|
int N = s1.length();
|
|
|
return process1(str1, str2, 0, 0, N);
|
|
|
}
|
|
|
|
|
|
// 返回str1[从L1开始往右长度为size的子串]和str2[从L2开始往右长度为size的子串]是否互为旋变字符串
|
|
|
// 在str1中的这一段和str2中的这一段一定是等长的,所以只用一个参数size
|
|
|
public static boolean process1(char[] str1, char[] str2, int L1, int L2, int size) {
|
|
|
if (size == 1) {
|
|
|
return str1[L1] == str2[L2];
|
|
|
}
|
|
|
// 枚举每一种情况,有一个计算出互为旋变就返回true。都算不出来最后返回false
|
|
|
for (int leftPart = 1; leftPart < size; leftPart++) {
|
|
|
if (
|
|
|
// 如果1左对2左,并且1右对2右
|
|
|
(process1(str1, str2, L1, L2, leftPart)
|
|
|
&& process1(str1, str2, L1 + leftPart, L2 + leftPart, size - leftPart)) ||
|
|
|
// 如果1左对2右,并且1右对2左
|
|
|
(process1(str1, str2, L1, L2 + size - leftPart, leftPart)
|
|
|
&& process1(str1, str2, L1 + leftPart, L2, size - leftPart))) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
public static boolean isScramble2(String s1, String s2) {
|
|
|
if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (s1 == null && s2 == null) {
|
|
|
return true;
|
|
|
}
|
|
|
if (s1.equals(s2)) {
|
|
|
return true;
|
|
|
}
|
|
|
char[] str1 = s1.toCharArray();
|
|
|
char[] str2 = s2.toCharArray();
|
|
|
if (!sameTypeSameNumber(str1, str2)) {
|
|
|
return false;
|
|
|
}
|
|
|
int N = s1.length();
|
|
|
int[][][] dp = new int[N][N][N + 1];
|
|
|
// dp[i][j][k] = 0 processDP(i,j,k)状态之前没有算过的
|
|
|
// dp[i][j][k] = -1 processDP(i,j,k)状态之前算过的,返回值是false
|
|
|
// dp[i][j][k] = 1 processDP(i,j,k)状态之前算过的,返回值是true
|
|
|
return process2(str1, str2, 0, 0, N, dp);
|
|
|
}
|
|
|
|
|
|
public static boolean process2(char[] str1, char[] str2, int L1, int L2, int size, int[][][] dp) {
|
|
|
if (dp[L1][L2][size] != 0) {
|
|
|
return dp[L1][L2][size] == 1;
|
|
|
}
|
|
|
boolean ans = false;
|
|
|
if (size == 1) {
|
|
|
ans = str1[L1] == str2[L2];
|
|
|
} else {
|
|
|
for (int leftPart = 1; leftPart < size; leftPart++) {
|
|
|
if ((process2(str1, str2, L1, L2, leftPart, dp)
|
|
|
&& process2(str1, str2, L1 + leftPart, L2 + leftPart, size - leftPart, dp))
|
|
|
|| (process2(str1, str2, L1, L2 + size - leftPart, leftPart, dp)
|
|
|
&& process2(str1, str2, L1 + leftPart, L2, size - leftPart, dp))) {
|
|
|
ans = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
dp[L1][L2][size] = ans ? 1 : -1;
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
public static boolean isScramble3(String s1, String s2) {
|
|
|
if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (s1 == null && s2 == null) {
|
|
|
return true;
|
|
|
}
|
|
|
if (s1.equals(s2)) {
|
|
|
return true;
|
|
|
}
|
|
|
char[] str1 = s1.toCharArray();
|
|
|
char[] str2 = s2.toCharArray();
|
|
|
if (!sameTypeSameNumber(str1, str2)) {
|
|
|
return false;
|
|
|
}
|
|
|
int N = s1.length();
|
|
|
boolean[][][] dp = new boolean[N][N][N + 1];
|
|
|
for (int L1 = 0; L1 < N; L1++) {
|
|
|
for (int L2 = 0; L2 < N; L2++) {
|
|
|
dp[L1][L2][1] = str1[L1] == str2[L2];
|
|
|
}
|
|
|
}
|
|
|
// 第一层for循环含义是:依次填size=2层、size=3层..size=N层,每一层都是一个二维平面
|
|
|
// 第二、三层for循环含义是:在具体的一层,整个面都要填写,所以用两个for循环去填一个二维面
|
|
|
// L1的取值氛围是[0,N-size],因为从L1出发往右长度为size的子串,L1是不能从N-size+1出发的,这样往右就不够size个字符了
|
|
|
// L2的取值范围同理
|
|
|
// 第4层for循环完全是递归函数怎么写,这里就怎么改的
|
|
|
for (int size = 2; size <= N; size++) {
|
|
|
for (int L1 = 0; L1 <= N - size; L1++) {
|
|
|
for (int L2 = 0; L2 <= N - size; L2++) {
|
|
|
for (int leftPart = 1; leftPart < size; leftPart++) {
|
|
|
if ((dp[L1][L2][leftPart] && dp[L1 + leftPart][L2 + leftPart][size - leftPart])
|
|
|
|| (dp[L1][L2 + size - leftPart][leftPart] && dp[L1 + leftPart][L2][size - leftPart])) {
|
|
|
dp[L1][L2][size] = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return dp[0][0][N];
|
|
|
}
|
|
|
|
|
|
}
|