洛谷 P1928 外星密码 (java,递归)
题目描述
有了防护伞,并不能完全避免 2012 的灾难。地球防卫小队决定去求助外星种族的帮助。经过很长时间的努力,小队终于收到了外星生命的回信。但是外星人发过来的却是一串密码。只有解开密码,才能知道外星人给的准确回复。解开密码的第一道工序就是解压缩密码,外星人对于连续的若干个相同的子串 X \texttt{X} X 会压缩为 [DX] \texttt{[DX]} [DX] 的形式( D D D 是一个整数且 1 ≤ D ≤ 99 1\leq D\leq99 1≤D≤99),比如说字符串 CBCBCBCB \texttt{CBCBCBCB} CBCBCBCB 就压缩为 [4CB] \texttt{[4CB]} [4CB] 或者 [2[2CB]] \texttt{[2[2CB]]} [2[2CB]],类似于后面这种压缩之后再压缩的称为二重压缩。如果是 [2[2[2CB]]] \texttt{[2[2[2CB]]]} [2[2[2CB]]] 则是三重的。现在我们给你外星人发送的密码,请你对其进行解压缩。
输入格式
输入一行,一个字符串,表示外星人发送的密码。
输出格式
输出一行,一个字符串,表示解压缩后的结果。
样例 #1
样例输入 #1
AC[3FUN]
样例输出 #1
ACFUNFUNFUN
———————————————————————————————
题解
简单地来说,就是在遍历每个字符时(将题目所给的字符串转为字符数组),如果是字母,就记录该字母;如果遇到左中括号 ‘[’ 时,就得考虑后面紧跟的是一个数字还是两个数字,确认好D之后,递归遍历后续字符,直到遇到右中括号 ‘]’,将其中的字母序列返回,然后紧接着在之前调用者函数中,重复记录该序列D次。如若遍历完了,并且最后一个字符不是右中括号 ‘]’,就返回所记录的字符串 s 。
在遇到左中括号 ‘[’ 时,如何判断数字?
首先,得清楚,字符 ‘0’ ~ ‘9’ 对应的ASCII码值为 48 ~ 57。
那么,字符 ‘6’ 的 ASCII码值为 54,减去字符’0’ 就可以得到 6。
char c = '6';
int c1 = (int) c;
int x = (int) (c - '0'); //减去并转为int
System.out.println("该字符为"+ c);
System.out.println("将'6'转为int的结果:" + c1);
System.out.println("'6'-'0'后的值为:" + x);
输出:
接下来,判断左中括号紧跟的数字 D
因为左中括号 '[ '后第一个字符必定是数字1 ~ 9,但第二个不确定,如果是数字,则范围为0 ~ 9,确定数字D。
另外, 如果是一位数,index (字符数组的索引) 应该后移两位。如果是两位数,index则后移三位。
// 由题意: '[' 后 , 是 个位数 或 两位数 (1 ~ 99)
int D = (int) (c[index + 1] - '0'); //第一位
int x = (int) (c[index + 2] - '0'); //第二位
index += 2; //后移两位
//如果左括号后第二个字符也是数字
if (x >= 0 && x <= 9) {
D = D * 10 + x; //两位数
index++; //之前后移了两位,此时后移一位即可
}
然后递归遍历后续字符,将递归调用返回的字符序列(s1)重复记录D次。用 s 记录。
//递归调用,将结果返回给s1
s1 = f(c);
//重复记录D次
while(D-- > 0) {
s += s1;
}
如果当前字符,既不是 左中括号 ‘[’ , 也不是 数字 呢?
如果是 字母, 就记录在字母序列 s 中。
如果是右中括号’ ] ',则将中括号内的字母序列 s 返回。
同时无论哪种选择,都不要忘记index后移。
if (c[index] == ']') {
index++;
return s; //返回中括号的字母序列
} else {
s += c[index]; //记录的字母序列
index++;
}
最后如果遍历完了,没有遇到中括号,或者假设原本内容没有压缩,就会发现上面语句,没有返回,所以在遍历完之后直接返回 记录内容 s。否则会出现:This method must return a result of type String 的问题。
最后附上完整AC代码:
import java.util.Scanner;
public class Main {
static int index = 0; //char[] c 的索引
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] s = sc.next().toCharArray();
sc.close();
System.out.println(f(s));
}
public static String f(char[] c) {
String s = "", s1;
while (index < c.length) {
if (c[index] == '[') {
// 由题意 '[' 后 , 是 个位数 或 两位数 (1 ~ 99)
int D = (int) (c[index + 1] - '0'); //第一位
int x = (int) (c[index + 2] - '0'); //第二位
index += 2;
//如果左括号后第二个字符也是数字
if (x >= 0 && x <= 9) {
D = D * 10 + x; //两位数
index++; //之前后移了两位,此时后移一位即可
}
s1 = f(c); //递归遍历后续内容,获取中括号内的字母序列
while(D-- > 0) {
s += s1;
}
} else {
if (c[index] == ']') {
index++;
return s; //返回中括号的字母序列
} else {
s += c[index]; //记录的字母序列
index++;
}
}
}
//遍历完了,不要忘了这一句返回
return s;
}
}