给定一个正整数 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" | |
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。 |
示例 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
解法一
public String countAndSay(int n) { | |
if (n == 1) return "1"; | |
if (n == 2) return "11"; | |
List<List<String>> result = new ArrayList<>(n); | |
// 初始化第一二个 | |
result.add(new ArrayList<>()<!--swig0-->); | |
result.add(new ArrayList<>()<!--swig1-->); | |
for (int i = 2; i < n; i++){ | |
// 前一个序列 | |
List<String> list = result.get(i - 1); | |
// 第一个值 | |
String value = list.get(0); | |
// 统计数量 | |
int number = 1; | |
// 统计当前序列 | |
List<String> newList = new ArrayList<>(); | |
// 从第二个开始,记录重复值数量 | |
for (int j = 1; j < list.size(); j++){ | |
// 如果相等,数量加一 | |
if (list.get(j).equals(value)){ | |
number++; | |
}else { | |
// 不等则将当前数记录,并统计下一个数 | |
newList.add(number + ""); | |
newList.add(value); | |
value = list.get(j); | |
number = 1; | |
} | |
} | |
// 记录最后一个值 | |
newList.add(number + ""); | |
newList.add(list.get(list.size() - 1)); | |
result.add(newList); | |
} | |
List<String> list = result.get(n - 1); | |
return String.join("", list); | |
} |
解法二
public String countAndSay1(int n) { | |
String result = "1"; | |
for (int i = 2; i <= n; i++){ | |
StringBuilder sb = new StringBuilder(); | |
// 当前数的下标 | |
int start = 0; | |
// 从左到右扫描的下标 | |
int pos = 0; | |
while (pos < result.length()){ | |
// 当前下标对应值等于扫描小标的值时,扫描下一个 | |
while (pos < result.length() && result.charAt(pos) == result.charAt(start)) { | |
pos++; | |
} | |
// 知道扫描的值与当前值不等时,记录数量与当前值 | |
sb.append(pos - start).append(result.charAt(start)); | |
// 并将当前值更新 | |
start = pos; | |
} | |
result = sb.toString(); | |
} | |
return result; | |
} |
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-and-say