外观数组(leetcode38)
给定一个正整数 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"
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。
然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。再将所有描述组连接起来。
解析:
两种方式,循环和递归
可以用一个变量记录一个描述组的字符,同时记录描述组字符的个数;
也可以直接记录一个描述组的开始索引,以及最后一个不相同的位置;
然后得到描述字符的个数,以及描述字符。最后注意边界条件,考虑n=1的情况,把边界加入;
package com.vincent.leetcode; public class leetcode38 { public static void main(String[] args) { // TODO Auto-generated method stub int n=8; System.out.println(countAndSay1(n)); } //循环 public static String countAndSay(int n) { if(n==1){ return "1"; } int i=1; StringBuilder result = new StringBuilder(); StringBuilder preResult = new StringBuilder(); preResult.append("1"); for(;i<n;i++){ Character ch; int count=1; int j=0; for(;j<preResult.length()-1;j++){ ch = preResult.charAt(j); if(preResult.charAt(j+1)==preResult.charAt(j)){//如果j位置的字符与j+1位置的字符相同,则count加1 count++; }else{//如果j和j+1位置的字符不同,则说明可以把该字符的个数和该字符加入结果了,然后count重置为1,开始统计下个字符连续出现的数量 result.append(count); result.append(ch); count=1; } } if(j<preResult.length()){//加入最后一个字符及它的个数 result.append(count); result.append(preResult.charAt(preResult.length()-1)); } preResult.delete(0, preResult.length());//清理上一个结果 preResult.append(result.toString()); result.delete(0, result.length()); } return preResult.toString(); } //循环 public static String countAndSay1(int n) { StringBuilder preResult = new StringBuilder(); //记录当前行的字符串,即n为i时对应的字符串 StringBuilder result = new StringBuilder(); preResult.append(1); for(int i=1;i<n;i++){ //记录每个数字的开始索引 int start = 0; for(int j=1;j<preResult.length();j++){ //当数字发生改变时执行 if(preResult.charAt(j)!=preResult.charAt(start)){ result.append(j-start).append(preResult.charAt(start)); start = j; } } //字符串最后一个字符,可以考虑i=1时; result.append(preResult.length()-start).append(preResult.charAt(start)); preResult.delete(0, preResult.length()); preResult.append(result); result.delete(0, result.length()); } return preResult.toString(); } //递归 public static String countAndSay2(int n) { //递归终止条件 if(n==1){ return "1"; } //获取到上一层的字符串 String preResult = countAndSay2(n-1); StringBuilder result = new StringBuilder(); //记录每个数字的开始索引 int start = 0; for(int i=1;i<preResult.length();i++){ //当数字发生改变时执行 if(preResult.charAt(i)!=preResult.charAt(start)){ result.append(i-start).append(preResult.charAt(start)); start = i; } } //字符串最后一个数字 result.append(preResult.length()-start).append(preResult.charAt(start)); return result.toString(); } }