You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
5.7 KiB

2 years ago
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];
}
}