练习题:外观数列
- 题目要求
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。
注意:整数序列中的每一项将表示为一个字符串。
示例 1:
输入: 1
输出: "1"
解释:这是一个基本样例。
示例 2:
输入: 4
输出: "1211"
解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 =
1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。
解:
设在上一行存在的数字为名词,那么这一行的字符串就是由一对一对的量词以及名词组成。例如:“一个一两个二三个一”就表达为“112231”。
那么我们每次都对出现的名词计数,并在前面加上他的数量,就是要得到的这一行的字符串。
先取一个头指针为=0,再取当前指针=1,遍历上一行的字符串(递归得到,第一行的字符串为“1”)。到当前指针所指的名词与头指针所指的名词不相同的时候,当前指针减头指针的值就是这个名词出现的次数(量词),将量词+名词(头指针指的数)拼入此行字符串即可。然后让头指针等于当前指针,继续遍历。
最后,如果头指针等于当前指针,说明上一行的字符串记录完了。如果头指针不等于当前指针,说明上一行字符串的最后几个名词相同,这时进行最后一次拼接即可。
代码实现(JAVA):
public static String countAndSay(int n) {
if(n==1){
return "1";
}
String s="";
int head = 0;
int now = 1;
String a=countAndSay(n-1);
for(;now<a.length();now++){
if(a.charAt(now)!=a.charAt(head)){
s+=(now-head+"");
s+=(a.charAt(head));
head=now;
}
}
if(head!=now){
int x=now-head;
s+=(x+"");
s+=(a.charAt(head));
}
return s;
}
这是根据以上的想法写的,后来看到评论区有大佬用StringBuilder进行字符串拼接,效率大大提升。于是修改代码如下:
public static String countAndSay(int n) {
if(n==1){
return "1";
}
StringBuilder s=new StringBuilder();
int head = 0;
int now = 1;
String a=countAndSay(n-1);
for(;now<a.length();now++){
if(a.charAt(now)!=a.charAt(head)){
s.append(now-head+"");
s.append(a.charAt(head));
head=now;
}
}
if(head!=now){
int x=now-head;
s.append(x+"");
s.append(a.charAt(head));
}
return s.toString();
}
来源:力扣(LeetCode)