

文章目录
摘要
这道题围绕的是一个非常常见但也非常容易写乱的逻辑:在原地压缩字符数组。我们要把连续的字符统计次数,然后按照"字符 + 次数"重新写回原数组。难点不是算法,而是各种边界情况,比如次数大于 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。掌握之后会对处理类似 "分段统计" 的问题非常有帮助。
核心记住三点:
- 用 read 统计,用 write 写回原数组
- 次数需要拆成字符写入,例如 12 → '1', '2'
- 最后返回 write 的位置作为结果长度