#hihocoder #1039 字符消除

  总结自己的代码能力,就是渣渣渣。找工作,看到各路大神高歌猛进,自己却…因此痛定思痛,困而学之,决定悔改自新,从头来过…

题目:#1039 : 字符消除

小Hi最近在玩一个字符消除游戏。给定一个只包含大写字母”AB C”的字符串s,消除过程是如下进行的:

  1. 如果s包含长度超过1的由相同字母组成的子串,那么这些子 串会被同时消除,余下的子串拼成新的字符串。例如”ABCCBCCC AA”中”CC”,”CCC”和”AA”会被同时消除,余下”AB”和”B”拼成新 的字符串”ABB”。

  2. 上述消除会反复一轮一轮进行,直到新的字符串不包含相邻的相同字符为止。例如”ABCCBCCCAA”经过一轮消除得到”ABB”,再经过一轮消除得到”A”

游戏中的每一关小Hi都会面对一个字符串s。在消除开始前小Hi有机会在s中任意位置(第一个字符之前、最后一个字符之后以及相邻两个字符之间)插入任意一个字符(‘A’,’B’或者’C’),得到字符串t。t经过一系列消除后,小Hi的得分是消除掉的字符的总数。

请帮助小Hi计算要如何插入字符,才能获得最高得分。

Input
输入第一行是一个整数T(1<=T<=100),代表测试数据的数量。
之后T行每行一个由’A”B”C’组成的字符串s,长度不超过100。
Output
对于每一行输入的字符串,输出小Hi最高能得到的分数。

Hint
第一组数据:在”ABCBCCCAA”的第2个字符后插入’C’得到”ABCCBCCCAA”,消除后得到”A”,总共消除9个字符(包括插入的’C’)。
第二组数据:”AAA”插入’A’得到”AAAA”,消除后得到”“,总共消除4个字符。
第三组数据:无论是插入字符后得到”AABC”,”ABBC”还是”ABCC”都最多消除2个字符。

Sample Input

3
ABCBCCCAA
AAA
ABC

Sample Output

9
4
2

  这道题目比较简单直接,主要考察对于字符的操作,需要依次遍历原字符串每个位置(共n+1个位置,假设字符串长度为n)分别添加‘A’,‘B’,‘C’的情况,一共有3*(n+1)种情况。然后对每种情况的字符串做处理。
依次判断相邻字符是否相等,设置一个计数变量。对于相等的情况,一开始的想法是对原字符串相应位置重置为一个不会出现的字符,比如‘D’,然后下一步再将其去除,递归处理新产生的字符串。对于新字符串长度为1,或者新旧字符串长度没有变化的,停止递归。

import java.util.Scanner;

public class Main {

    private static void earse(String input) {
        int res = 0;
        int max = 0;
        char[] cArray = new char[input.length() + 1];
        char[] change = {'A', 'B', 'C'};
        for (int k = 0; k < 3; k++) {
            for (int i = 0; i < input.length() + 1; i++) {
                cArray[i] = change[k];
                for (int j = 0; j < i; j++) {
                    cArray[j] = input.charAt(j);
                }
                for (int j = i + 1; j < input.length() + 1; j++) {
                    cArray[j] = input.charAt(j-1);
                }
                res = earse(cArray);
                if (res > max) {
                    max = res;
                }
            }
        }
        System.out.println(max);
    }

    private static int earse(char[] cArray) {
        if (cArray.length <= 1) {
            return 0;
        }
        int res = 0;
        for (int i = 0; i < cArray.length; i++) {
            int cnt = 1;
            while (i < cArray.length - 1 && cArray[i+1] == cArray[i]) {
                i++;
                cnt++;
            }
            res += (cnt != 1 ? cnt : 0);
            if (cnt != 1) {
                for (int j = i + 1 - cnt; j <= i; j++) {
                    cArray[j] = 'D';
                }
            }
        }
        if (String.valueOf(cArray).matches(".*D.*") && cArray.length - res >= 2) {
            char[] nChar = new char[cArray.length - res];
            int j = 0;
            for (int i = 0; i < cArray.length; i++) {
                if (cArray[i] != 'D') {
                    nChar[j++] = cArray[i];
                }
            }
            return res + earse(nChar);
        } else {
            return res;
        }
    }

    public static void main(String[] args) {
        Scanner sin = new Scanner(System.in);
        int N = sin.nextInt(); 
        while(N-- != 0){
            String P = sin.next();
            earse(P);
        }
    }

}

  由于有对字符的操作,一开始使用了char数组,操作比较繁琐,后来考虑使用了String类,题目中对String的拼接较多,因此使用了Stringbuilder类。本来StringBuilder的操作比char数组慢一些,但是char数组什么需要提前定义大小,因此中间多了一步关于‘D’的操作,总体速度反而满了。

import java.util.Scanner;

public class Main {
    private static void earse(StringBuilder input) {
        int res = 0;
        int max = 0;
        StringBuilder cArray = new StringBuilder(); 
        char[] change = {'A', 'B', 'C'};
        for (int k = 0; k < 3; k++) {
            for (int i = 0; i < input.length() + 1; i++) {
                if (i == 0) {
                    cArray.append(change[k]).append(input);
                } else if (i == input.length()) {
                    cArray.append(input).append(change[k]);
                } else {
                    cArray.append(input.subSequence(0, i))
                    .append(change[k]).
                    append(input.subSequence(i, input.length()));
                }
                res = earse2(cArray);
                if (res > max) {
                    max = res;
                }
                cArray.delete(0, cArray.length());
            }
        }
        System.out.println(max);
    }

    private static int earse2(StringBuilder cArray) {
        if (cArray.length() <= 1) {
            return 0;
        }
        int res = 0;
        StringBuilder nChar = new StringBuilder();
        for (int i = 0; i < cArray.length(); i++) {
            int cnt = 1;
            while (i < cArray.length() - 1 && cArray.charAt(i+1) == cArray.charAt(i)) {
                i++;
                cnt++;
            }
            if (cnt == 1) {
                // 使用正向添加,不是反向删除,速度略有加快
                nChar.append(cArray.charAt(i)); 
            } else {
                res += cnt;   
            }
        }
        if (cArray.length() - nChar.length() > 0 
            && nChar.length() >= 2) {
            return res + earse2(nChar);
        } else {
            return res;
        }
    }

    public static void main(String[] args) {
        Scanner sin = new Scanner(System.in);
        int N = sin.nextInt(); 
        while(N-- != 0){
            String P = sin.next();
            earse(new StringBuilder(P));
        }
    }
}

  微末道行,暂时就这样了,有时间再多修改自己的代码。过阵子回头来看自己,觉得自己当初怎么这么渣就对了,表面那是功力比现在好…

Java中的知识点:
1.String类与StringBuilder类的区别

  • 对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象
  • String str=”hello world”和String str=new String(“hello world”)的区别(是否产生新的对象)
  • String、StringBuffer以及StringBuilder的区别(是否产生新的字符串、线程安全)

2.char数组与String类的区别

你可能感兴趣的:(java,hihoCoder)