当前位置: 首页 > article >正文

LeetCode 443 压缩字符串

字符数组压缩算法详解:实现与分析

一、引言

在处理字符数组时,我们常常遇到需要对连续重复字符进行压缩的场景。这不仅可以节省存储空间,还能提升数据传输效率。本文将深入解析一个经典的字符数组压缩算法,通过详细的实现步骤和原理分析,帮助读者全面理解这一算法。

二、问题详细描述

给定一个字符数组 chars,请使用以下算法进行压缩:

  1. 从一个空字符串 s 开始。

  2. 对于 chars 中的每组连续重复字符:

    • 如果这一组长度为 1,则将字符追加到 s 中。

    • 否则,需要向 s 追加字符,后跟这一组的长度。例如,字符 'a' 连续出现 3 次,则压缩为 "a3"

  3. 压缩后得到的字符串 s 不应该直接返回,需要转储到字符数组 chars 中。如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。例如,长度为 12 的组将被写为 '1''2' 两个字符。

  4. 修改完输入数组后,返回该数组的新长度。

三、解题思路:双指针法

3.1 算法原理

为了高效地在原地完成字符数组的压缩,我们采用双指针技术。双指针法通过两个指针 readwrite 分别负责读取和写入操作,能够在一次遍历中完成压缩,无需额外的空间。

3.2 详细步骤

  1. 初始化指针readwrite 指针都从 0 开始。

  2. 读取字符read 指针用于遍历字符数组,找到每组连续重复字符。

  3. 计数:对于每个字符,计算其连续出现的次数。这通过一个循环实现,每次检查下一个字符是否与当前字符相同,如果是,则计数加 1。

  4. 写入字符:将当前字符写入 write 指针位置。然后根据计数决定是否需要写入数字。

  5. 写入计数:如果计数大于 1,则将计数转换为字符串,并逐个字符写入 write 指针后续位置。例如,计数为 12 时,写入 '1''2'

  6. 移动指针read 指针移动到下一组字符的起始位置,write 指针根据写入的字符数量移动。

3.3 优势

双指针法的优势在于:

  • 高效性:仅需一次遍历即可完成压缩,时间复杂度为 O(n),其中 n 是数组长度。

  • 空间效率:所有操作在原数组上进行,无需额外存储结构,空间复杂度为 O(1)。

四、算法实现

以下是 Java 实现代码:

class Solution {public int compress(char[] chars) {if (chars == null || chars.length == 0) return 0;int write = 0;int n = chars.length;for (int read = 0; read < n; ) {char current = chars[read];int count = 1;// 计算连续字符的长度while (read + count < n && chars[read + count] == current) {count++;}// 写入当前字符chars[write++] = current;// 如果计数大于 1,写入计数if (count > 1) {String s = String.valueOf(count);for (char c : s.toCharArray()) {chars[write++] = c;}}// 移动读取指针到下一组字符read += count;}return write;}
}

五、代码详细解析

5.1 初始化

if (chars == null || chars.length == 0) return 0;
int write = 0;
int n = chars.length;
  • 首先检查输入数组是否为空或长度为 0。如果是,则直接返回 0。

  • 初始化 write 指针为 0,用于跟踪写入位置。

  • 获取数组长度 n,用于后续循环控制。

5.2 外层循环:遍历字符数组

for (int read = 0; read < n; ) {char current = chars[read];int count = 1;
  • read 指针从 0 开始,遍历整个数组。

  • 对于每个 read 位置的字符,将其存储在 current 中,并初始化计数为 1。

5.3 内层循环:计算连续字符长度

while (read + count < n && chars[read + count] == current) {count++;
}
  • 检查 read + count 是否在数组范围内,并且下一个字符是否与 current 相同。

  • 如果是,则计数加 1,直到遇到不同的字符或数组末尾。

5.4 写入字符

chars[write++] = current;
  • 将当前字符写入 write 指针位置,并将 write 指针向前移动一位。

5.5 写入计数

if (count > 1) {String s = String.valueOf(count);for (char c : s.toCharArray()) {chars[write++] = c;}
}
  • 如果计数大于 1,则将计数转换为字符串。

  • 遍历字符串的每个字符,并将其逐个写入数组。例如,计数为 12 时,写入 '1''2'

5.6 移动读取指针

read += count;
  • read 指针移动到下一组字符的起始位置,继续处理下一组字符。

六、算法分析

6.1 时间复杂度

该算法的时间复杂度为 O(n),其中 n 是字符数组的长度。每个字符仅被处理一次,无论是读取还是写入操作。内层循环虽然看似增加了复杂度,但实际上每个字符只被检查一次,因此总的时间复杂度仍然是线性的。

6.2 空间复杂度

空间复杂度为 O(1),因为我们没有使用任何与输入规模相关的额外存储结构。所有操作都在原数组上进行,仅使用了几个变量来辅助操作。

七、示例分析

示例 1

输入chars = ['a', 'a', 'b', 'b', 'c', 'c', 'c']

步骤解析

  1. read = 0current = 'a',计数为 2。

    • 写入 'a'write = 1

    • 写入 '2'write = 2

    • read 移动到 2。

  2. read = 2current = 'b',计数为 2。

    • 写入 'b'write = 3

    • 写入 '2'write = 4

    • read 移动到 4。

  3. read = 4current = 'c',计数为 3。

    • 写入 'c'write = 5

    • 写入 '3'write = 6

    • read 移动到 7,循环结束。

输出:数组变为 ['a', '2', 'b', '2', 'c', '3'],新长度为 6。

示例 2

输入chars = ['a']

步骤解析

  1. read = 0current = 'a',计数为 1。

    • 写入 'a'write = 1

    • 因为计数为 1,不写入数字。

    • read 移动到 1,循环结束。

输出:数组仍为 ['a'],新长度为 1。

示例 3

输入chars = ['a', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b']

步骤解析

  1. read = 0current = 'a',计数为 1。

    • 写入 'a'write = 1

    • read 移动到 1。

  2. read = 1current = 'b',计数为 12。

    • 写入 'b'write = 2

    • 写入 '1''2'write = 4

    • read 移动到 13,循环结束。

输出:数组变为 ['a', 'b', '1', '2'],新长度为 4。

八、常见问题解答

Q1:为什么选择双指针法?

双指针法能够高效地在原地完成数组的压缩。它通过两个指针分别负责读取和写入操作,避免了使用额外的存储空间。这种方法在时间复杂度和空间复杂度上都具有显著优势,特别适合处理这类原地修改的问题。

Q2:如何处理计数大于 9 的情况?

当计数大于 9 时,将计数转换为字符串,然后逐个字符写入数组。例如,计数为 12 时,写入 '1''2'。这种方法确保了所有计数都能正确表示,无论其大小如何。

Q3:算法是否适用于所有长度的数组?

是的。该算法适用于所有长度的数组,包括空数组、单个字符数组以及包含多个重复字符组的数组。在代码开头,我们对空数组进行了特殊处理,返回 0。对于其他情况,算法都能正确处理。

九、总结

字符数组压缩算法是一个典型的原地操作问题,通过双指针法能够在 O(n) 时间复杂度和 O(1) 空间复杂度下完成任务。该算法的核心在于高效地识别连续重复字符组,并将它们转换为压缩形式。通过详细解析和示例分析,我们希望读者能够深入理解这一算法的原理和实现细节。

相关文章:

LeetCode 443 压缩字符串

字符数组压缩算法详解&#xff1a;实现与分析 一、引言 在处理字符数组时&#xff0c;我们常常遇到需要对连续重复字符进行压缩的场景。这不仅可以节省存储空间&#xff0c;还能提升数据传输效率。本文将深入解析一个经典的字符数组压缩算法&#xff0c;通过详细的实现步骤和…...

datasheet数据手册-阅读方法

DataSheet Datasheet&#xff08;数据手册&#xff09;&#xff1a;电子元器件或者芯片的数据手册&#xff0c;一般由厂家编写&#xff0c;格式一般为PDF&#xff0c;内容为电子分立元器件或者芯片的各项参数&#xff0c;电性参数&#xff0c;物理参数&#xff0c;甚至制造材料…...

AI绘制流程图,方法概述

1 deepseek 生成图片的mermaid格式代码&#xff0c;在kimi中进行绘图或在jupter notebook中绘制&#xff1a; 或在draw.io中进行绘制&#xff08;mermaid代码&#xff09; 2 svg是矢量图&#xff0c;可以插入到word """mermaid graph TDA[基线解算] --> B[北…...

ObjectOutputStream 深度解析

ObjectOutputStream 深度解析 ObjectOutputStream 是 Java IO 体系中的一个关键类,用于序列化(将对象转换为字节流),通常与 ObjectInputStream 配合使用,实现对象的持久化存储或网络传输。 1.作用:完成对象的序列化过程 2.它可以将JVM当中的Java对象序列化到文件中/网…...

git回滚指定版本并操作

你可以通过以下步骤切换到第三个版本。根据你的需求&#xff0c;有两种主要方法&#xff1a; 方法 1&#xff1a;临时查看第三个版本&#xff08;不修改当前分支&#xff09; 适用于仅查看或测试旧版本&#xff0c;不保留后续修改&#xff1a; 找到第三个版本的提交哈希&#…...

【AI插件开发】Notepad++ AI插件开发实践:支持配置界面

一、引用 此前的系列文章已基本完成了Notepad的AI插件的功能开发&#xff0c;但是此前使用的配置为JSON配置文件&#xff0c;不支持界面配置。 本章在此基础上集成支持配置界面&#xff0c;这样不需要手工修改配置文件&#xff0c;直接在界面上操作&#xff0c;方便快捷。 注…...

polkitd服务无法启动导致docker无法启动问题解决

问题docker服务无法启动&#xff0c;溯源发现是polkit服务没有正确运行 systemctl status polkit可以看到类似提示 Sep 18 02:58:24 server1 dbus[897]: [system] Failed to activate service org.freedesktop.PolicyKit1: timed out Sep 18 02:59:29 server1 systemd[1]: po…...

软件工程中数据一致性的探讨

软件工程中数据一致性的探讨 引言数据一致性&#xff1a;软件工程中的业务正确性与性能的权衡数据一致性为何重要业务正确性&#xff1a;事务的原子性与一致性ACID原则的基石分布式事务的挑战一致性级别&#xff1a;从强一致到最终一致 实践中的一致性权衡金融系统&#xff1a;…...

数据库原理及应用mysql版陈业斌实验四

&#x1f3dd;️专栏&#xff1a;Mysql_猫咪-9527的博客-CSDN博客 &#x1f305;主页&#xff1a;猫咪-9527-CSDN博客 “欲穷千里目&#xff0c;更上一层楼。会当凌绝顶&#xff0c;一览众山小。” 目录 实验四索引与视图 1.实验数据如下 student 表&#xff08;学生表&…...

华为OD机试真题——最长的顺子(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析&#xff1b; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式&#xff01; 本文收录于专栏&#xff1a;《2025华为OD真题目录全流程解析/备考攻略/经验…...

【HTML】html文件

HTML文件全解析&#xff1a;搭建网页的基石 在互联网的广袤世界里&#xff0c;每一个绚丽多彩、功能各异的网页背后&#xff0c;都离不开HTML文件的默默支撑。HTML&#xff0c;即超文本标记语言&#xff08;HyperText Markup Language&#xff09;&#xff0c;作为网页创建的基…...

使用 XWPFDocument 生成表格时固定列宽度

一、XWPFDocument XWPFTable个性化属性 1.初始默认写法 XWPFTable table document.createTable(n, m); //在文档中创建一个n行m列的表格 table.setWidth("100%"); // 表格占页面100%宽度// 通过getRow获取行进行自定义设置 XWPFTableRow row table.getRow(0); XW…...

足球AI模型:一款用数据分析赛事的模型

2023 年欧冠决赛前&#xff0c;某体育数据平台的 AI 模型以 78% 的概率预测曼城夺冠 —— 最终瓜迪奥拉的球队首次捧起大耳朵杯。当足球遇上 AI&#xff0c;那些看似玄学的 "足球是圆的"&#xff0c;正在被数据与算法拆解成可计算的概率命题。今天我们就来聊聊&#…...

【ESP32|音频】一文读懂WAV音频文件格式【详解】

简介 最近在学习I2S音频相关内容&#xff0c;无可避免会涉及到关于音频格式的内容&#xff0c;所以刚开始接触的时候有点一头雾水&#xff0c;后面了解了下WAV相关内容&#xff0c;大致能够看懂wav音频格式是怎么样的了。本文主要为后面ESP32 I2S音频系列文章做铺垫&#xff0…...

万向死锁的发生

我是标题 1.欧拉角2.万向死锁 参考&#xff1a;小豆8593 1.欧拉角 欧拉角在Unity中描述的是一种变换&#xff08;Transform&#xff09;共有3个轴体&#xff0c;默认顺序为x->y->z. 2.万向死锁 可以把万向死锁的情况理解成&#xff1a;由于轴体旋转的顺序是固定的&am…...

JavaScript学习教程,从入门到精通,JavaScript BOM (Browser Object Model) 详解(18)

JavaScript BOM (Browser Object Model) 详解 1. BOM 介绍 BOM (Browser Object Model) 是浏览器对象模型&#xff0c;它提供了独立于内容而与浏览器窗口进行交互的对象。BOM的核心对象是window&#xff0c;它表示浏览器的一个实例。 BOM包含的主要对象&#xff1a; window…...

人工智能与云计算:技术融合与实践

1. 引言 人工智能(AI)和云计算是当今科技领域最具变革性的两项技术。AI通过模拟人类智能解决问题,而云计算则提供了弹性可扩展的计算资源。两者的结合创造了前所未有的可能性,使企业能够以更低的成本部署复杂的AI解决方案。 本文将探讨AI与云计算的技术融合,包括核心概念、…...

42.[前端开发-JavaScript高级]Day07-手写apply-call-bind-块级作用域

手写apply-call-bind <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…...

ObjectInputStream 终极解析与记忆指南

ObjectInputStream 终极解析与记忆指南 一、核心本质 ObjectInputStream 是 Java 提供的对象反序列化流,继承自 InputStream,用于读取由ObjectOutputStream序列化的Java对象。 核心特性速查表 特性说明继承链InputStream → ObjectInputStream核心功能实现Java对象反序列化…...

数据结构有哪些类型(对于数据结构的简述)

在学习计算机时&#xff0c;数据结构是不可忽视的一点&#xff0c;从考研时的408课程&#xff0c;再到工作中编写软件&#xff0c;网站&#xff0c;要想在计算机领域站住脚跟&#xff0c;数据结构是必备的 在这里&#xff0c;我对于数据结构进行了汇总&#xff0c;并简要描述&…...

Vscode 插件开发

文章目录 1、使用vscode官方插件生成框架&#xff0c;下载脚手架2、使用脚手架初始化项目&#xff0c;这里我选择的是js3、生成的文件结构如下&#xff0c;重要的就是以下两个文件4、代码5、打包使用6、发布官网地址7、publisher ID undefined provided in the extension manif…...

C# string和其他引用类型的区别

在C#中&#xff0c;字符串&#xff08;String&#xff09;和其他引用类型&#xff08;Reference Types&#xff09;之间有几个关键的区别&#xff0c;这些区别主要体现在它们的内存管理、赋值行为以及使用方式上。 1. 内存管理 字符串&#xff08;String&#xff09;&#xff1…...

RTT添加一个RTC时钟驱动,以DS1307为例

添加一个外部时钟芯片 这里多了一个选项 复制drv_rtc.c,重命名为drv_rtc_ds1307.c 添加到工程中 /*** @file drv_rtc_ds1307.c* @brief * @author jiache (wanghuan3037@fiberhome.com)* @version 1.0* @date 2025-01-08* * @copyright Copyright (c) 2025 58* */ #...

常见的低代码策略整理

低代码策略通过简化开发流程、降低技术门槛、提升效率&#xff0c;帮助用户快速构建灵活可靠的应用。这些策略的核心优势体现在以下方面&#xff1a; 快速交付与降本增效 减少编码需求&#xff1a;通过可视化配置&#xff08;如变量替换、表达式函数&#xff09;替代传统编码…...

从彩色打印单行标准九九表学习〖代码情书〗的书写范式(Python/DeepSeek)

写给python终端的情书&#xff0c;学习代码设计/书写秘笈。 笔记模板由python脚本于2025-04-17 12:49:08创建&#xff0c;本篇笔记适合有python编程基础的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思考与经验&#xff0c;而不仅仅是知识的简…...

QML与C++:基于ListView调用外部模型进行增删改查(附自定义组件)

目录 引言相关阅读项目结构文件组织 核心技术实现1. 数据模型设计联系人项目类 (datamodel.h)数据模型类 (datamodel.h)数据模型实现 (datamodel.cpp) 2. 主程序入口点 (main.cpp)3. 主界面设计 (Main.qml)4. 联系人对话框 (ContactDialog.qml)5. 自定义组件CustomTextField.qm…...

postman莫名奇妙报错,可能是注释引起的。postman 过滤请求体中的注释。

postman莫名奇妙报错&#xff0c;可能是注释引起的。postman 过滤请求体中的注释。 1、问题描述2、问题分析3、解决方法 1、问题描述 postman http请求测试时&#xff0c;如果在请求体中添加了注释&#xff0c;那么这个注释会被带到服务端执行&#xff0c;导致服务端接口返回报…...

扩增子分析|基于R语言microeco包进行微生物群落网络分析(network网络、Zi-Pi关键物种和subnet子网络图)

一、引言 microeco包是福建农林大学姚敏杰教授团队开发的扩增子测序集成分析。该包综合了扩增子测序下游分析的多种功能包括群落组成、多样性、网络分析、零模型等等。通过简单的几行代码可实现复杂的分析。因此&#xff0c;microeco包发表以来被学界广泛关注&#xff0c;截止2…...

中间件--ClickHouse-4--向量化执行(什么是向量?为什么向量化执行的更快?)

1、向量&#xff08;Vector&#xff09;的概念 &#xff08;1&#xff09;、向量的定义 向量&#xff1a;在计算机科学中&#xff0c;向量是一组同类型数据的有序集合&#xff0c;例如一个包含多个数值的数组。在数据库中&#xff0c;向量通常指批量数据&#xff08;如一列数…...

TDengine 存储引擎剖析:数据文件与索引设计(一)

TDengine 存储引擎简介 在物联网、工业互联网等快速发展的今天&#xff0c;时间序列数据呈爆发式增长。这些数据具有产生频率高、依赖采集时间、测点多信息量大等特点&#xff0c;对数据存储和处理提出了极高要求。TDengine 作为一款高性能、分布式、支持 SQL 的时序数据库&am…...