这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
前言
力扣第三十八题 外观数列 如下所示:
给定一个正整数 n ,输出外观数列的第 n 项。
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = "1"countAndSay(n)是对countAndSay(n-1)的描述,然后转换成另一个数字字符串。
示例 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"
一、思路
这一题题目特别长,需要多看两遍才能明白是什么意思。这一题主要有一个比较重要的信息:
- 外观数列的定义:递归公式定义的数字字符串序列
因为 n 对应的数列是对 n-1 对应的外观数列的描述,所以很明显我们可以通过递归来生成 n 对应的外观数列。
但是如何通过 n-1 对应的外观数列生成 n 对应的外观数列呢?
举个例子
我们可以通过下面这个例子来具象化:已知 n=4 对应的外观数列为 1211,那么 n=5 对应的外观数列是什么呢?
tips:我们知道
n=5对应的外观数列是对n=4的描述,在描述中需要将相同的值连读。比如1211中有两个连续的1需要读做两个 1
大致的思路分为以下几步:
i=0:i为遍历的下标
- 从左至右遍历
n=4的外观数列1211,只要相邻的两个值不相等就记录结果 i = 0时,拿到字符串1i = 1时,拿到字符串2。此时相邻的两个值不相同记录结果一个 1i = 2时,拿到字符串1。此吃相邻的两个值不相同记录结果一个 2i = 3时,拿到字符串1。此吃相邻的值相同,但为最后一个字符串,也许记录结果两个 1- 最终结果为
一个1 一个2 两个 1,即111221
上面这个遍历过程用双指针可以有效的减少存储一个字符串的空间,所以在实现中就是使用双指针+递归来做的。.
二、实现
实现代码
实现代码与思路中保持一致
public String countAndSay(int n) {
if (n == 1)
return "1";
else {
String val = countAndSay(n -1);
return explain(val);
}
}
/**
* 双指针:描述某个值
*/
public String explain(String val) {
StringBuilder sb = new StringBuilder();
char[] arr = val.toCharArray();
int left = 0;
int right = 0;
while (right < arr.length) {
// 不相等
if (arr[left] != arr[right]) {
sb.append(right - left).append(arr[left]);
// 移动左指针
left = right;
}
// 是否为最后一个元素
if (right == arr.length -1) {
sb.append(right - left + 1).append(arr[left]);
}
right ++;
}
return sb.toString();
}
测试代码
public static void main(String[] args) {
String ret = new Number38().countAndSay(5);
System.out.println(ret);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥