【刷穿 LeetCode】38. 外观数列 :「模拟」&「打表」

简介: 【刷穿 LeetCode】38. 外观数列 :「模拟」&「打表」

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 38. 外观数列 ,难度为 简单


Tag : 「模拟」


给定一个正整数 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


模拟



一个朴素的想法是:根据题意进行模拟,从起始条件 k = 1k=1ans = "1" 出发,逐步递推到 k = nk=n 的情况,对于第 kk 项而言,其实就是对第 k - 1k1 项的「连续段」的描述,而求「连续段」长度,可以使用双指针实现。


代码:


class Solution {
    public String countAndSay(int n) {
        String ans = "1";
        for (int i = 2; i <= n; i++) {
            String cur = "";
            int m = ans.length();
            for (int j = 0; j < m; ) {
                int k = j + 1;
                while (k < m && ans.charAt(j) == ans.charAt(k)) k++;
                int cnt = k - j;
                cur += cnt + "" + ans.charAt(j);
                j = k;
            }
            ans = cur;
        }
        return ans;
    }
}
复制代码


  • 时间复杂度:O(n^2)O(n2)
  • 空间复杂度:O(n)O(n)


打表



利用数据范围只有 3030,我们可以使用 static 进行打表操作,从而节省掉不同样例之间的「重复」部分的计算量。


例如对于 n = 5n=5n = 6n=6 都存在先计算前五项的公共部分,打表可以确保这部分只会被计算一次,同时能够应用到后面项中。


代码:


class Solution {
    static String[] f = new String[35];
    static {
        f[1] = "1";
        for (int i = 2; i < 35; i++) {
            String prev = f[i - 1], cur = "";
            int m = prev.length();
            for (int j = 0; j < m; ) {
                int k = j + 1;
                while (k < m && prev.charAt(j) == prev.charAt(k)) k++;
                int cnt = k - j;
                cur += cnt + "" + prev.charAt(j);
                j = k;
            }
            f[i] = cur;
        }
    }
    public String countAndSay(int n) {
        return f[n];
    }
}
复制代码


  • 时间复杂度:将打表逻辑到放本地执行,复杂度为 O(1)O(1);放到 OJOJ 执行则为 O(n^2)O(n2)
  • 空间复杂度:O(C)O(C)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.38 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
2月前
Leetcode第38题(外观数列)
LeetCode第38题要求生成外观数列的第n项,该数列从数字1开始,每一项都是对前一项的描述,例如第1项是"1",第2项是"11",第3项是"21",以此类推。
34 0
|
4月前
|
存储
LeetCode------斐波那契数列(2)
这篇文章提供了解决LeetCode上"斐波那契数列"问题的两种方法:一种是使用备忘录模式通过递归计算并存储结果以避免重复计算,另一种是自底向上的迭代方法,同时要求结果对1e9+7取模。
LeetCode------斐波那契数列(2)
|
7月前
leetcode-38:外观数列
leetcode-38:外观数列
43 0
|
算法 安全 Swift
LeetCode - #38 外观数列
不积跬步,无以至千里;不积小流,无以成江海,Swift社区 伴你前行。如果大家有建议和意见欢迎在文末留言,我们会尽力满足大家的需求。
LeetCode - #38 外观数列
【leetcode每日一题】1027. 最长等差数列
【leetcode每日一题】1027. 最长等差数列
leetcode剑指offer53–n-1中缺失的数字(二分//or等差数列)
leetcode剑指offer53–n-1中缺失的数字(二分//or等差数列)
|
Java C语言
LeetCode刷题计划——单调数列
LeetCode刷题计划——单调数列
102 0
|
存储 Python
LeetCode 38. 外观数列
给定一个正整数 n ,输出外观数列的第 n 项。
100 0
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
124 2