给定一个正整数 n ,输出外观数列的第 n 项,这是一个经典的算法,leetcode上也有此题,今天我们详细分析一下。
1、题目简介如下:
/** * 给定一个正整数 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" * 要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量, * 然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。 * */
2、解题思路采用递归方案循环调用;
3、测试代码如下:
public static void main(String[] args) {
System.out.println(countAndSay1(3));
}
/**
* 递归法
* 题目的意思是对序列前一个数进行报数,数列第一项是1,那第二项就报第一项的有1个1,输出11,
* 然后第三项就在第二项的基础上报数,第二项是11,第三项不就是2个1么,然后输出21。
* 由于每次得到的数据都是来源于上一次的结果,所以我们可以假设得到了上次的结果,继而往后运,所以直接递归,只有 30 个,无需考虑栈溢出。
* @param n
* @return
*/
private static String countAndSay1(int n) {
if(n < 1){
return "";
}
if(n == 1){
return "1";
}
char[] last = countAndSay1(n - 1).toCharArray();//此项就是在上一项的基础上处理
StringBuilder ans = new StringBuilder();
int times = 1;
for(int i = 1;i < last.length; i++){
if(last[i - 1] == last[i]){//如果和上一位的值一样就加一
times++;
}else {
ans.append(String.valueOf(times));//如果不一样了,就临时保存起来
ans.append(String.valueOf(last[i - 1]));
times = 1;//初始化1
}
}
/**
* 最后一次的添加数据
*/
ans.append(String.valueOf(times));
ans.append(String.valueOf(last[last.length-1]));
return ans.toString();
}
伪代码简洁明了,大家认真查看联系,定会早日掌握。