【中等】力扣算法题解析LeetCode38:外观数列

关注文末的名片达文汐,回复关键词“力扣源码”,即可获取完整源码!!详见:源码和核心代码的区别

题目详情

「外观数列」是一个数位字符串序列,由递归公式定义:

  • countAndSay(1) = "1"
  • countAndSay(n) countAndSay(n-1) 的行程长度编码。
    行程长度编码(RLE)是一种字符串压缩方法,其工作原理是通过将连续相同字符(重复两次或更多次)替换为字符重复次数(运行长度)和字符的串联。例如,要压缩字符串 "3322251" ,我们将 "33" "23" 替换,将 "222" "32" 替换,将 "5" "15" 替换并将"1""11" 替换。因此压缩后字符串变为"23321511"

给定一个整数 n ,返回外观数列的第 n 个元素。

示例 1:
输入:n = 4
输出:“1211”
解释:
countAndSay(1) = “1”
countAndSay(2) = “1” 的行程长度编码 = “11”
countAndSay(3) = “11” 的行程长度编码 = “21”
countAndSay(4) = “21” 的行程长度编码 = “1211”

示例 2:
输入:n = 1
输出:“1”
解释:这是基本情况。

提示:

  • 1 <= n <= 30

解题思路

  1. 问题分析:外观数列的第 n 项依赖于第 n-1 项,可以通过迭代逐步生成。需要高效处理字符串的行程编码。
  2. 核心优化
    • 双指针高效统计:使用快慢指针统计连续字符,减少循环次数
    • 预分配空间:根据前一项长度估算新字符串容量(2倍),减少扩容开销
    • 原地构建:直接操作字符数组,避免 charAt() 的边界检查开销
  3. 关键操作
    • 初始化当前字符串为 "1"
    • 对于每个迭代步骤:
      • 将字符串转为字符数组,避免多次调用 charAt()
      • 快指针扫描连续相同字符,慢指针标记起始位置
      • 直接计算连续字符长度(快慢指针差值)
      • 将长度和字符拼接到 StringBuilder
    • 更新当前字符串为下一项
  4. 边界处理:当 n=1 时直接返回 "1"

代码实现(Java版)

class Solution {
    public String countAndSay(int n) {
        // 基本情况处理
        if (n == 1) return "1";
        
        // 初始化为第一项
        String current = "1";
        
        // 迭代生成第2到第n项
        for (int i = 2; i <= n; i++) {
            // 预分配空间(新字符串长度不超过前一项2倍)
            StringBuilder sb = new StringBuilder(current.length() * 2);
            // 转为字符数组提高访问效率
            char[] chars = current.toCharArray();
            int slow = 0;  // 慢指针:连续字符起始位置
            int fast = 0;  // 快指针:扫描连续字符
            
            // 双指针遍历字符数组
            while (fast < chars.length) {
                // 移动快指针直到遇到不同字符
                while (fast < chars.length && chars[fast] == chars[slow]) {
                    fast++;
                }
                // 计算连续字符长度
                int count = fast - slow;
                // 拼接出现次数和字符
                sb.append(count).append(chars[slow]);
                // 移动慢指针到新的连续起始位置
                slow = fast;
            }
            // 更新当前字符串
            current = sb.toString();
        }
        
        return current;
    }
}

代码说明

  1. 初始化处理:当 n=1 时直接返回初始值 "1"
  2. 迭代优化
    • 使用字符数组 chars 存储当前字符串,减少 charAt() 调用开销
    • 双指针(slowfast)高效统计连续字符:
      • slow 标记连续字符起始位置
      • fast 扫描至连续字符结束位置
      • 连续字符长度 = fast - slow
  3. 高效拼接
    • 预分配 StringBuilder 容量为前一项长度的2倍
    • 直接使用 append() 拼接整数和字符
  4. 复杂度分析
    • 时间复杂度:O(L) 每轮迭代,L 为当前字符串长度
    • 空间复杂度:O(L) 存储当前字符串和字符数组

提交详情(执行用时、内存消耗)

在这里插入图片描述

我的名片👇👇👇👇👇👇👇👇👇👇👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达文汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值