这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战
今天又是一个周五,又到了本周盘点的时间。每次这个时候,都会有一个疑惑:我这周到底干啥了?感觉每天特别忙碌,但是又感觉一周下来,手上的事情没什么特别的进展。
本周在开始的时候做了一个计划,列出了待办5个工作事项,经过了一周艰难的努力,虽然这5个处理的差不多了,但是待办事项从5个变成了10个。
不过本周也不是一无是处,锻炼次数多了,乒乓球团体赛也赢了,下周继续保持锻炼吧。
更文挑战已经第27天了,本月到目前为止还不错,保持了每天1题,每天更文,今天继续做leetcode的第38题。
题目
给定一个正整数 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" 的描述如下图:
思路
也没啥特别的算法,就类似菲波那切数列,从头开始一个个往后计算呗,理解了题意就好。
根据f(n-1)计算f(n)的时候,可以用到快慢指针,这也是一个经典的算法了:
先定义2个指针fast和slow分别指向下标1和0,然后对比fast和slow的值是否相同,相同就把fast向后移动1位,继续比较,直到出现不同,这时数字就是slow指向的数字,个数就是fast-slow。
需要注意的是,最后1种数据在循环里面还未包含,因为最后fast会超过len,所以别忘记最后拼接上,个数为len-slow。
Java版本代码
class Solution {
public String countAndSay(int n) {
if (n == 1) {
return "1";
} else {
String pre = countAndSay(n - 1);
int len = pre.length();
StringBuilder ans = new StringBuilder();
int slow = 0;
int fast = 1;
while (fast < len) {
if (pre.charAt(slow) != pre.charAt(fast)) {
ans.append(fast-slow).append(pre.charAt(slow));
slow = fast;
fast++;
} else {
fast++;
}
}
// 最后1种数字还要加上
ans.append(len-slow).append(pre.charAt(slow));
return ans.toString();
}
}
}