题设
给定一个正整数 n ,输出外观数列的第 n 项。
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = "1"
countAndSay(n)
是对 countAndSay(n-1)
的描述,然后转换成另一个数字字符串。
外观数列前五项
1. 1
2. 11
3. 21
4. 1211
5. 111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
要描述 一个数字字符串,首先要将字符串分割为最小数量的组,每个组都由连续的最多相同字符组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
例如,数字字符串 “3322251” 的描述如下图:
示例
输入:n = 1
输出:"1"
解释:这是一个基本样例。
输入:n = 4
输出:"1211"
解释:
countAndSay(1) = "1"
countAndSay(2) = 读 "1" = 一 个 1 = "11"
countAndSay(3) = 读 "11" = 二 个 1 = "21"
countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"
提示
1 <= n <= 30
题解
- 就我而言使用递归解决问题比较符合我对题目的直观理解,递归出口为n==1返回值为“1”
- 如果n!=1,则需要进行处理,根据n-1对应的字符串找到第n个字符串,将处理过程抽象成
getSequence(String s)
方法,s即为第n-1个外观序列对应的字符串,也就是countAndSay(n-1)
的返回值 - 对我而言,搞清楚递归的过程,对于第n-1个字符串的处理相对而言就比较简单一些。我最初的想法是新建一个Node结点,记录当前的字符和其本次出现的次数,看过一些题解后发现
StringBuffer
更符合题目的情形。定义StringBuffer result
用于存放结果,定义一个currentChar
用于保存即将存入StringBuffer
的字符,定义计数器count
记录currentChar
的出现次数。遍历过程中如果出现新字符,就把currentChar
和count
存入result
中。注意,此时新字符已经出现一次,所以新字符的出现次数已经是1,更新currentChar
和count
即可 - 循环结束时,将当时的
currentChar
和count
存入result
即可
代码如下
public static String countAndSay(int n){
//递归出口
if(n == 1){
return "1";
} else{
/*
如果非1,则根据当前n-1的返回值
通过getSequence(String)函数处理n-1的字符串得到第n个字符串
*/
return getSequence(countAndSay(n-1));
}
}
public static String getSequence(String s){
//计数器,记录当前字符重复次数
int count = 0;
int len = s.length();
//记录即将被写入StringBuffer的字符
char currentChar = s.charAt(0);
//result记录当前字符串s的返回结果
StringBuffer result = new StringBuffer();
//遍历s的每个字符
for (int i = 0; i < len; i++) {
//如果当前的i指向的字符同currentChar相等说明当前字符重复,count加一
if (s.charAt(i) == currentChar){
count++;
}else {
//否则说明出现新字符,将旧的currentChar存入result,count修改为1
result.append(count);
result.append(currentChar);
currentChar = s.charAt(i);
count=1;
}
}
//循环结束,将最后的一个currentChar存入结果
result.append(count);
result.append(currentChar);
return result.toString();
}