洛谷 P1928 外星密码 (java,递归)

洛谷 P1928 外星密码 (java,递归)

题目描述

有了防护伞,并不能完全避免 2012 的灾难。地球防卫小队决定去求助外星种族的帮助。经过很长时间的努力,小队终于收到了外星生命的回信。但是外星人发过来的却是一串密码。只有解开密码,才能知道外星人给的准确回复。解开密码的第一道工序就是解压缩密码,外星人对于连续的若干个相同的子串 X \texttt{X} X 会压缩为 [DX] \texttt{[DX]} [DX] 的形式( D D D 是一个整数且 1 ≤ D ≤ 99 1\leq D\leq99 1D99),比如说字符串 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;
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dnasZJ2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值