题目描述
报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
- 1
- 11
- 21
- 1211
- 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”
我的解法
string countAndSay(int n) {
string last_count;
string now_count;
if (n == 1){ return "1"; }
if (n == 2){ return "11"; }
last_count = "11";
for (int i = 3; i <= n; i++) //第几次报数的循环
{
int j = 0; // 慢指针
now_count = "";
while (j < last_count.size() - 1)
{
int temp = 1; // 重复个数
int k = j + 1; // 快指针
while (last_count[j] == last_count[k])
{
temp++;
k++;
}
char temp_char[10];
sprintf_s(temp_char, "%d", temp);
now_count = now_count + temp_char;
now_count.push_back(last_count[j]);
j = k;
}
// 处理最后一位
if (last_count[last_count.size() - 1] != last_count[last_count.size() - 2])
{
now_count.push_back('1');
now_count.push_back(last_count[last_count.size() - 1]);
}
last_count = now_count;
}
return now_count;
}
- 思考延伸
- sprintf和sprintf_s
sprintf_s是sprintf的安全版本,指定缓冲区长度来避免sprintf()存在的溢出风险,主要差在sprintf_s第二个参数,可以控制缓冲区大小 - strlen(*char) 和sizeof()
strlen(*char)函数求是字符串的实际长度,它可以用来获取动态实际字符数组的长度,是从开始到遇到第一个“\0”,如果只是定义没有赋予初始值,这个结果是不确定的,它会从数组的首地址开始一直找下去,直到遇到“\0”停止查找。
sizeof()求所占总空间的字节数,静态的,跟初始状态字符数组的大小有关系,大小等于初始时字符数组的大小或者等于初始时字符数组的大小+1。 - C++中char类型可以自动转换成string类型,即你可以用char类型字符串直接给string类型变量赋值。但反过来是不行的。
递归解法
思路:用的递归思想,观察发现每一个结果和前一个结果有关,出口是第一个报数。
string countAndSay1(int n)
{
if (n == 1){ return "1"; }
string str_last = countAndSay(n - 1);
string str_now;
int count = 1;
for (int i = 0; i < str_last.size(); i++)
{
if (str_last[i] == str_last[i + 1])
{
count++;
}
else
{
str_now += to_string(count) + str_last[i];
count = 1;
}
}
return str_now;
}
-
我的疑惑
对于字符串strlast访问到第strlast.size()个元素不会报数组溢出bug吗? -
解答
字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
因此最后字符串的末尾还是会有一个‘\0’字符,因此不会有溢出的bug,当然再往后访问一个就出错了。 -
其它收获
- 递归思想:程序的下一层输入为上一层的输出,即函数参数为上一次函数运算的返回值
- to_string函数:.c++11标准增加了全局函数std::to_string