Leetcode 38. 外观数列
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情。
1、题目📑
给定一个正整数 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
2、思路🧠
方法一:字符串模拟
本题的难点在于有些小伙伴在看了题目之后没有明白题目的意图💔。那让厂长简单和大家解释一下。
- 1
- 2 描述的是1,是一个1,也就是11
- 3 描述的是11,是两个1,也就是21
- 4 描述的是21,是一个2一个1,也就是12-11
- 5 描述的是1211, 是一个1,一个2,两个1,也就是11-12-21
- 6 描述的是111221,是三个1,两个2,一个1,也就是31-22-11
- 7 描述的是312211,是一个3一个1两个2两个1,也即是13-11-22-21
- 以此类推
递归实现:
根据此题目会想到一个经典的递归题目的公式 F(n) = F(n - 1) ,此题目和这个公式相似,只是解法不同。
-
分析题目得到递归的终止条件为
n == 1 -
当
n > 1时,需要拿到countAndSay(n - 1)的字符串,并对字符串中每个数字的个数计算:- 对于计算字符串中每个数字出现的个数,定义一个变量
count进行统计。 - 通过for循环来遍历每个字符串中所有的数字,这里要注意每次统计完一组数字就要
清1的操作 - 通过while循环计算字符串中每个数字出现的个数,以及当前计算的数字是什么。
- 最后通过StringnBuffer对其进行拼接处理,得到结果。
- 对于计算字符串中每个数字出现的个数,定义一个变量
方法二:字符串模拟➕双指针
解法与方法一类似,在判断字符串重复字符的时候巧用了双指针来计算当前数的个数。
废话少说~~~~~上代码!
3、代码👨💻
第一次commit AC
class Solution {
public String countAndSay(int n) {
if(n == 1) return "1";
String num = countAndSay(n - 1);
StringBuffer sb = new StringBuffer();
for (int i = 0; i <= num.length() - 1; i++) {
int count = 1;
while(i < num.length() - 1 && num.charAt(i) == num.charAt(i + 1)) {
count++;
i++;
}
sb.append(count);
sb.append(num.charAt(i));
}
return sb.toString();
}
}
时间复杂度:O(N2)
空间复杂度:O(N)
第二次commit AC
class Solution {
public String countAndSay(int n) {
if(n == 1) return "1";
String num = countAndSay(n - 1);
StringBuffer sb = new StringBuffer();
int i = 0, j = 1, len = num.length();
while(j < len) {
if (num.charAt(i) != num.charAt(j)) {
sb.append(j - i).append(num.charAt(i));
i = j;
}
j++;
}
sb.append(j - i).append(num.charAt(i));
return sb.toString();
}
}
4、总结
该题目的对思维的分析与探讨,对于题目的解读能力是非常关键的,在力扣的刷题过程中,字符串的问题还是比较多的,在解决字符串的问题要灵活分析应用合适的方法进行拆解并提交。
❤️来自专栏《LeetCode基础算法题》欢迎订阅❤️
厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。
对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!