字符消消乐
描述
有一个字符消除游戏,给定一个只包含大写字母‘ABC’的字符串s,消除过程是如下进行的:
-
如果s包含长度超过1的由相同字母组成的子串,那么这些子串会被同时消除,余下的子串拼成新的字符串。例如"ABCCBCCCAA"中“CCC“和"AA”会被同时消除,余下“AB”
-
上述消除会反复一轮一轮进行,直到新的字符串不包含相邻的相同字符为止。例如”ABCCBCCAA”经过一轮消除得到“ABB”,再经过一轮消除得到“A”
在消除开始前有机会在s中任意位置(第一个字符之前、最后一个字符之后以及相邻两个字符之间)插入输入的一个字符(‘A’,‘B’或者‘C’),得到字符串t。字符串除后,游戏最终得分是消除掉的字符的总数。
计算要如何插入字符,才能获得最高得分。
Input
输入第一行是插入的字符(‘A’ ‘B’或者‘C’)。
输入第二行是由’A"B"C组成的字符串s,长度不超过100。
Output
输出游戏的最高能得到的分数。
消除字符串部分代码
/**
* 进行字符串的消除
* @param str 需要被消除的字符串
* @return 消除完成的字符串
*/
private static String replace(String str) {
//跳出递归的条件
int q = 0;
//从第0位开始遍历
//adsadddaaawqewssa
for (int i = 0; i < str.length(); ) {//i==3
//记录当前字符的位置 因为一旦消除 后面的字符就会移动这一位
int m = i;//4
//取当前下标的字符
char c = str.charAt(i);//d
int j = i + 1;//5
for (; j < str.length(); j++) {
if (c == str.charAt(j)) {
continue;
}
break;
}
//j=7
if (j - i > 1) {
q++;//代表当前字符串中还有需要消除的
//adssaaaasqewssa
str = str.substring(0, i) + str.substring(j);
//因为被消除了 那么后面的字符串就会移动到之前的位置
i = m;
continue;
}
i++;
}
if (q == 0) {
return str;
}
return replace(str);
}
在执行字符串相邻并且相同的消除操作的时候,需要先判断后面一位是否是与前面一位相同的,如过相同,就需要一个值来进行记录,判断应该消除几个字符串,消除之后,后面的字符串就会移动到当前位置,所以我们需要一个值来记录被消除之前的下标。
第一次消除之后,后面的字符串会往前移动,相邻位置又可能有相同的字符串,所以我这里使用了递归进行下一次的判断消除。
进行插入操作部分代码
/**
* 进行插入操作
* @param str 需要进行判断消除的字符串
* @return 被插入的字符串的位置
*/
private static int insert(String str) {
//两个指针 差距最大的
int max = 0;
int index = 0;//记录插入的位置
//4 cbabc
for (int i = 1; i < str.length(); i++) {
//k前移动 j后移动 ABABCBABABACBBCBAB
for (int k = i - 1, j = i + 1; k >= 0 && j < str.length(); k--, j++) {
if (str.charAt(k) == str.charAt(j)) {
if (k - 1 >= 0 && j + 1 < str.length()) {
continue;
}
}
if (j - k > max) {
max = j - k;
index = i;
}
break;
}
if (max > (str.length() - i) * 2) {
break;
}
}
return index;
}
该方法使用的是双指针法,传入需要被插入一个字符,并且插入字符之后消除得最多的字符串,定义j、k两个指针,k向前移动,j向后移动,如果他们所在的位置的字符串相同就直接再次移动,直到不相等。
完整代码
/**
* 字符消消乐
* @author young先森00
*/
public class Test {
public static void main(String[] args) {
//ABABCBACBCBAB
//ABABCBABABABCBCBAB
//ABABCBABABACBBCBAB
String begin = "CAABBCABAAACCABCBACCBABAABBABCBCBAB";
String str = replace(begin);
System.out.println("第一次消除的结果为" + str);
//插入
int i = insert(str);
System.out.println("在第:" + i + "位插入:" + str.charAt(i));
String s = str.substring(0, i) + str.charAt(i) + str.substring(i);
System.out.println("插入后字符串变为:" + s);
//插入后再次消除得到最终结果
String end = replace(s);
System.out.println("消除的最终结果为:" + end);
System.out.println("插入后最后得分为:" + (begin.length() - end.length()));
}
/**
* 进行插入操作
* @param str 需要进行判断消除的字符串
* @return 被插入的字符串的位置
*/
private static int insert(String str) {
//两个指针 差距最大的
int max = 0;
int index = 0;//记录插入的位置
//4 cbabc
for (int i = 1; i < str.length(); i++) {
//k前移动 j后移动 ABABCBABABACBBCBAB
for (int k = i - 1, j = i + 1; k >= 0 && j < str.length(); k--, j++) {
if (str.charAt(k) == str.charAt(j)) {
if (k - 1 >= 0 && j + 1 < str.length()) {
continue;
}
}
if (j - k > max) {
max = j - k;
index = i;
}
break;
}
if (max > (str.length() - i) * 2) {
break;
}
}
return index;
}
/**
* 进行字符串的消除
* @param str 需要被消除的字符串
* @return 消除完成的字符串
*/
private static String replace(String str) {
//跳出递归的条件
int q = 0;
//从第0位开始遍历
//adsadddaaawqewssa
for (int i = 0; i < str.length(); ) {//i==3
//记录当前字符的位置 因为一旦消除 后面的字符就会移动这一位
int m = i;//4
//取当前下标的字符
char c = str.charAt(i);//d
int j = i + 1;//5
for (; j < str.length(); j++) {
if (c == str.charAt(j)) {
continue;
}
break;
}
//j=7
if (j - i > 1) {
q++;//代表当前字符串中还有需要消除的吧 1
//adssaaaasqewssa
str = str.substring(0, i) + str.substring(j);
//因为被消除了 那么后面的字符串就会移动到之前的位置
i = m;
continue;
}
i++;
}
if (q == 0) {
return str;
}
return replace(str);
}
}