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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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];
}
}