小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
题目描述
给定一个正整数 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"
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
例如,数字字符串 "3322251" 的描述如下图:
示例 1:
输入:n = 1
输出:"1"
解释:这是一个基本样例。
示例 2:
输入:n = 4
输出:"1211"
解释:
countAndSay(1) = "1"
countAndSay(2) = 读 "1" = 一 个 1 = "11"
countAndSay(3) = 读 "11" = 二 个 1 = "21"
countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"
提示:
1 <= n <= 30
思考过程
1.刚开始用将int拆分出数字进行前后两个判断,然后再次拼接成int.对其进行循环.
后来报错了,长度不够..
2.使用数组存储,长度就足够了.使用数组代替存储int,那么循环数组,对其进行前后判断(注意边界值,到最后一位会溢出,就增加一位)
3.看评论,可以使用字符串直接进行存储操作,不需要数据存储,进一步节省空间
题解
1.使用数组存储
使用集合存储循环的结果,作为入参再次带入循环.
- 初始化数组为1,进行一次运算,因此入参的次数要-1;
- 对数组的结尾增加一位,防止与下一位比较时溢出.并且在最后一位后会结束循环,因此在与结尾的比较的结果要不相同触发逻辑
- 内循环结束,将新的数组替换旧的数组.
- 外循环结束,对数组进行翻转,然后转换成string
List<Integer> integers = new ArrayList<>();
// 初始化数组为1
integers.add(1);
// 初始化数组默认算一次,因此入参的次数-1
for (int i = 0; i < n - 1; i++) {
int tem = 0;
// 默认次数为1
int count = 1;
List<Integer> integers1 = new ArrayList<>();
int resultCount = integers.size();
// 增加一位,防止数组溢出
integers.add(0);
for (int j = 0; j < resultCount; j++) {
if (tem == 0) {
tem = integers.get(j);
}
if (tem == integers.get(j+1)) {
count ++;
}
else {
integers1.add(tem);
integers1.add(count);
count = 1;
tem = 0;
}
}
integers = integers1;
}
Collections.reverse(integers);
// 使用StringBuilder 效率比String高
StringBuilder stringBuilder = new StringBuilder();
for (int ns : integers) {
stringBuilder.append(ns);
}
return stringBuilder.toString();
2.使用String直接拼接
改进点 :
- 临时变量temp在为0时存储当前元素,当判断为不同时,变成0. → 临时变量开始存储第一位,当判断为不用时,存储为不同的那个变量.
- 在数组后面增加一位0防止边界溢出,因此当到达最后一位时必定不同并且跳出循环 → 循环结束,将最后的结果再存入字符串中
- 使用数组存储,最后再转换成string. → 直接将数据存储在string中,转换成char数组,最后直接输出
StringBuilder temp = new StringBuilder("1");
char[] chars = null;
char c = ' ';
for (int i = 0; i < n -1; i++) {
int count = 1;
chars = temp.toString().toCharArray();
// 存储不用的元素.当比较不相等时,将不同的值存入.循环结束再放入结果即可
c = chars[0];
temp = new StringBuilder("");
for (int j = 1; j < chars.length; j++) {
if (c == chars[j]) {
count ++;
}
// 不相等时,写入并且重置
else {
temp.append(c);
temp.append(count);
count = 1;
c = chars[j];
}
}
// 将最后一次的数据存入
temp.append(c);
temp.append(count);
}
return temp.reverse().toString();