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.

177 lines
4.9 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 class46;
// 如果一个字符相邻的位置没有相同字符,那么这个位置的字符出现不能被消掉
// 比如:"ab"其中a和b都不能被消掉
// 如果一个字符相邻的位置有相同字符,就可以一起消掉
// 比如:"abbbc"中间一串的b是可以被消掉的消除之后剩下"ac"
// 某些字符如果消掉了,剩下的字符认为重新靠在一起
// 给定一个字符串,你可以决定每一步消除的顺序,目标是请尽可能多的消掉字符,返回最少的剩余字符数量
// 比如:"aacca", 如果先消掉最左侧的"aa",那么将剩下"cca",然后把"cc"消掉,剩下的"a"将无法再消除返回1
// 但是如果先消掉中间的"cc",那么将剩下"aaa"最后都消掉就一个字符也不剩了返回0这才是最优解。
// 再比如:"baaccabb"
// 如果先消除最左侧的两个a剩下"bccabb"
// 如果再消除最左侧的两个c剩下"babb"
// 最后消除最右侧的两个b剩下"ba"无法再消除返回2
// 而最优策略是:
// 如果先消除中间的两个c剩下"baaabb"
// 如果再消除中间的三个a剩下"bbb"
// 最后消除三个b不留下任何字符返回0这才是最优解
public class Code03_DeleteAdjacentSameCharacter {
// 暴力解
public static int restMin1(String s) {
if (s == null) {
return 0;
}
if (s.length() < 2) {
return s.length();
}
int minLen = s.length();
for (int L = 0; L < s.length(); L++) {
for (int R = L + 1; R < s.length(); R++) {
if (canDelete(s.substring(L, R + 1))) {
minLen = Math.min(minLen, restMin1(s.substring(0, L) + s.substring(R + 1, s.length())));
}
}
}
return minLen;
}
public static boolean canDelete(String s) {
char[] str = s.toCharArray();
for (int i = 1; i < str.length; i++) {
if (str[i - 1] != str[i]) {
return false;
}
}
return true;
}
// 优良尝试的暴力递归版本
public static int restMin2(String s) {
if (s == null) {
return 0;
}
if (s.length() < 2) {
return s.length();
}
char[] str = s.toCharArray();
return process(str, 0, str.length - 1, false);
}
// str[L...R] 前面有没有跟着[L]字符has T 有 F 无
// L,R,has
// 最少能剩多少字符,消不了
public static int process(char[] str, int L, int R, boolean has) {
if (L > R) {
return 0;
}
if (L == R) {
return has ? 0 : 1;
}
int index = L;
int K = has ? 1 : 0;
while (index <= R && str[index] == str[L]) {
K++;
index++;
}
// index表示第一个不是[L]字符的位置
int way1 = (K > 1 ? 0 : 1) + process(str, index, R, false);
int way2 = Integer.MAX_VALUE;
for (int split = index; split <= R; split++) {
if (str[split] == str[L] && str[split] != str[split - 1]) {
if (process(str, index, split - 1, false) == 0) {
way2 = Math.min(way2, process(str, split, R, K != 0));
}
}
}
return Math.min(way1, way2);
}
// 优良尝试的动态规划版本
public static int restMin3(String s) {
if (s == null) {
return 0;
}
if (s.length() < 2) {
return s.length();
}
char[] str = s.toCharArray();
int N = str.length;
int[][][] dp = new int[N][N][2];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < 2; k++) {
dp[i][j][k] = -1;
}
}
}
return dpProcess(str, 0, N - 1, false, dp);
}
public static int dpProcess(char[] str, int L, int R, boolean has, int[][][] dp) {
if (L > R) {
return 0;
}
int K = has ? 1 : 0;
if (dp[L][R][K] != -1) {
return dp[L][R][K];
}
int ans = 0;
if (L == R) {
ans = (K == 0 ? 1 : 0);
} else {
int index = L;
int all = K;
while (index <= R && str[index] == str[L]) {
all++;
index++;
}
int way1 = (all > 1 ? 0 : 1) + dpProcess(str, index, R, false, dp);
int way2 = Integer.MAX_VALUE;
for (int split = index; split <= R; split++) {
if (str[split] == str[L] && str[split] != str[split - 1]) {
if (dpProcess(str, index, split - 1, false, dp) == 0) {
way2 = Math.min(way2, dpProcess(str, split, R, all > 0, dp));
}
}
}
ans = Math.min(way1, way2);
}
dp[L][R][K] = ans;
return ans;
}
public static String randomString(int len, int variety) {
char[] str = new char[len];
for (int i = 0; i < len; i++) {
str[i] = (char) ((int) (Math.random() * variety) + 'a');
}
return String.valueOf(str);
}
public static void main(String[] args) {
int maxLen = 16;
int variety = 3;
int testTime = 100000;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int len = (int) (Math.random() * maxLen);
String str = randomString(len, variety);
int ans1 = restMin1(str);
int ans2 = restMin2(str);
int ans3 = restMin3(str);
if (ans1 != ans2 || ans1 != ans3) {
System.out.println(str);
System.out.println(ans1);
System.out.println(ans2);
System.out.println(ans3);
System.out.println("出错了!");
break;
}
}
System.out.println("测试结束");
}
}