题目描述
给定一个正整数 n ,输出外观数列的第 n 项。
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = “1”
countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。
前五项如下:
-
1
-
11
-
21
-
1211
-
111221
第一项是数字 1
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 “11”
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 “21”
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 “1211”
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 “111221”
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
例如,数字字符串 “3322251” 的描述如下图:
题解
递归求解,如果n等于1则返回1的string,如果n>1,先得到f(n-1)的字符串,对n-1字符串进行分析后生成新的字符串返回。
如何对f(n-1)字符串进行分析:
1. 递归出口,当n==1时,返回string=“1”
2. 对f(n-1)进行分析,从string的第一个字符开始遍历,遍历索引为i,如果第 i 个字符与第 i+1 个字符相等,则进入内循环,用count记录连续的字符个数(count初始化为1,表示没有两个或以上的连续字符),每轮循环结束都能得到 count 个 字符类型为char(count最小为 1 ),然后将 count (需要转换为 char 类型,我用的是map)和 字符ch 依次加入 vector 数组尾部。所以循环结束后 结果字符串就是 vector 中的顺序遍历。
- 代码
#include<vector>
#include<cstring>
class Solution {
public:
string countAndSay(int n) {
vector<char> arr;
unordered_map<int,char> mp = {
{1,'1'},
{2,'2'},
{3,'3'},
{4,'4'},
{5,'5'},
{6,'6'},
{7,'7'},
{8,'8'},
{9,'9'}
};
if(n==1)
{
string s="1";
return s;
}else{
string s=countAndSay(n-1);
int i=0; //表示遍历索引
while(i<s.size())
{
char ch = s[i];
//如果有连续
int count=1; //表示连续相同字符的数量
while(i<s.size()-1&&ch==s[i+1])
{
count++;
i++;
}
i++;
//这时候有 count个ch
char num=mp[count];
arr.push_back(num);
arr.push_back(ch);
}
//将vector转换为string
string ch;
ch.clear();
ch.assign(arr.begin(),arr.end());
return ch;
}
}
};