LeetCode 443. 压缩字符串


文章目录

摘要

这道题围绕的是一个非常常见但也非常容易写乱的逻辑:在原地压缩字符数组。我们要把连续的字符统计次数,然后按照"字符 + 次数"重新写回原数组。难点不是算法,而是各种边界情况,比如次数大于 9、数组最后一段如何处理、怎么做到原地覆盖等等。

为了让整个过程更容易理解,我把解法拆成了两个指针的移动逻辑,并准备了一个可运行的 Swift Demo,你可以直接在 Xcode 或 Swift Playground 中跑起来验证。

描述

题目要求我们对一个字符数组做压缩,规则是遍历数组中 连续重复的字符,然后:

  • 如果某个字符只出现一次,就直接写回该字符;
  • 如果字符重复出现,比如 5 次,就写回 "字符" + "5"
  • 并且压缩后的结果要覆盖原数组,不能开新的数组。

最终输出的是压缩后数组的"有效长度",数组后面剩余的字符可以忽略。

举个例子:

txt 复制代码
输入: ["a","a","b","b","c","c","c"]
压缩后: ["a","2","b","2","c","3"]
返回 6

看起来简单,但操作过程中涉及大量"边界处理"和指针移动,一不小心就容易写乱。

3# 题解答案

最常见的实现方式是:

  • read 指针遍历原数组;
  • write 指针把压缩后的内容写回;
  • 在处理一段连续字符后,把字符和计数按顺序写入。

整体就是一个标准的 "双指针" + "分段处理" 的问题。

题解代码分析(含可运行 Demo)

下面是一个可以直接运行的 Swift 代码示例,其中包含 main 方法(适合 Swift Playground)。

swift 复制代码
import Foundation

class Solution {
    func compress(_ chars: inout [Character]) -> Int {
        var write = 0      // 写指针,指向压缩后要写入的位置
        var read = 0       // 读指针,遍历字符数组
        
        while read < chars.count {
            let currentChar = chars[read]
            var count = 0
            
            // 统计当前字符的连续重复次数
            while read < chars.count && chars[read] == currentChar {
                read += 1
                count += 1
            }
            
            // 写入字符
            chars[write] = currentChar
            write += 1
            
            // 写入次数(如果次数大于1)
            if count > 1 {
                for digit in String(count) {
                    chars[write] = digit
                    write += 1
                }
            }
        }
        
        return write
    }
}


// MARK: - Demo 测试代码
func runDemo() {
    var chars1: [Character] = ["a","a","b","b","c","c","c"]
    var chars2: [Character] = ["a"]
    var chars3: [Character] = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
    
    let sol = Solution()
    
    print("原数组 1:", chars1)
    let len1 = sol.compress(&chars1)
    print("压缩后:", Array(chars1.prefix(len1)), "长度:", len1)
    print()
    
    print("原数组 2:", chars2)
    let len2 = sol.compress(&chars2)
    print("压缩后:", Array(chars2.prefix(len2)), "长度:", len2)
    print()
    
    print("原数组 3:", chars3)
    let len3 = sol.compress(&chars3)
    print("压缩后:", Array(chars3.prefix(len3)), "长度:", len3)
}

runDemo()

示例测试及结果

运行上面的 Demo,可以看到如下输出(我在这里帮你整理成清晰的形式):

示例 1

输入:

txt 复制代码
["a","a","b","b","c","c","c"]

输出:

txt 复制代码
["a","2","b","2","c","3"]
长度 = 6

示例 2

输入:

txt 复制代码
["a"]

输出:

txt 复制代码
["a"]
长度 = 1

示例 3

输入:

txt 复制代码
["a","b","b","b","b","b","b","b","b","b","b","b","b"]

输出:

txt 复制代码
["a","b","1","2"]
长度 = 4

这里 "b" 重复了 12 次,所以变成 "b12"

与实际场景结合

这类"压缩字符串"的操作在真实开发中比想象中常见,比如:

1. 日志压缩

很多移动端或物联网设备会生成大量日志,但带宽有限,所以会对重复内容压缩传输。类似 "AAAAABB""A5B2",就是很常见的一种日志优化方式。

2. 数据同步传输优化

例如某些设备上传传感器数据,如果连续数据相同,可以大幅减少传输量,降低服务器压力。

3. UI 文本处理

比如聊天 App 中用户输入 "hhhhhhh" 时,可以处理成 "h7" 存储,降低消息体积。

我们在做实际业务时,经常会需要对连续数据分段统计重复值,这题就是个非常小巧但很典型的数据压缩基础模型。

时间复杂度

整个算法通过 read 指针遍历了一遍数组,不会有重叠或回退。

  • 时间复杂度:O(n)
    每个字符最多被读一次、写一次。

空间复杂度

  • 空间复杂度:O(1)
    压缩结果直接写回原数组,未开辟额外空间(输出不计入空间消耗)。

总结

这道题虽然逻辑不难,但对"指针移动"、"边界处理"、"次数拆分"为字符等细节要求很高,容易写出 Bug。掌握之后会对处理类似 "分段统计" 的问题非常有帮助。

核心记住三点:

  1. 用 read 统计,用 write 写回原数组
  2. 次数需要拆成字符写入,例如 12 → '1', '2'
  3. 最后返回 write 的位置作为结果长度
相关推荐
TracyCoder1238 分钟前
LeetCode Hot100(26/100)——24. 两两交换链表中的节点
leetcode·链表
望舒5132 小时前
代码随想录day25,回溯算法part4
java·数据结构·算法·leetcode
铉铉这波能秀2 小时前
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
数据结构·python·算法·leetcode·哈希算法
参.商.2 小时前
【Day 27】121.买卖股票的最佳时机 122.买卖股票的最佳时机II
leetcode·golang
铉铉这波能秀3 小时前
LeetCode Hot100数据结构背景知识之元组(Tuple)Python2026新版
数据结构·python·算法·leetcode·元组·tuple
铉铉这波能秀4 小时前
LeetCode Hot100数据结构背景知识之字典(Dictionary)Python2026新版
数据结构·python·算法·leetcode·字典·dictionary
我是咸鱼不闲呀4 小时前
力扣Hot100系列20(Java)——[动态规划]总结(下)( 单词拆分,最大递增子序列,乘积最大子数组 ,分割等和子集,最长有效括号)
java·leetcode·动态规划
唐梓航-求职中4 小时前
编程-技术-算法-leetcode-288. 单词的唯一缩写
算法·leetcode·c#
Ll13045252984 小时前
Leetcode二叉树part4
算法·leetcode·职场和发展
@––––––4 小时前
力扣hot100—系列4-贪心算法
算法·leetcode·贪心算法