LeetCode 面试题 01.06. 字符串压缩(443. 压缩字符串)

2023-12-26 18:04

本文主要是介绍LeetCode 面试题 01.06. 字符串压缩(443. 压缩字符串),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 对于算法题,按题型类别刷题才会更有成效,因此我这里在网上搜索并参考了下 “🔥 LeetCode 热题 HOT 100” 的题型归类,并在其基础上做了一定的完善,希望能够记录自己的刷题历程,有所收获!点击下发链接跳转~⬇️⬇️⬇️

🔥 LeetCode 热题 HOT 100【题型归类汇总,助力刷题】

面试题 01.06. 字符串压缩

   

字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。

示例1:

 输入:"aabcccccaaa"
 输出:"a2b1c5a3"

示例2:

 输入:"abbccd"
 输出:"abbccd"
 解释:"abbccd"压缩后为"a1b2c2d1",比原字符串长度更长。

提示:

  1. 字符串长度在[0, 50000]范围内。

思路:参考 LeetCode题解

根据题意,需要将「连续相同字符」压缩为「字符+出现次数」的格式。例如:aaa→a3,b→b1,aabbb→a2b3

双指针法

  • 分别定义下标 i = 0(慢指针),j = 1 (快指针)。
  • 令 i 指向字符串的「首个字符」, j 向前遍历,直到访问到「不同字符」时停止,此时 j−i 便是「首个字符」的连续出现次数,即可完成首个字符的压缩操作。
  • 接下来,从下个字符开始,重复以上操作,直到遍历完成即可。
  • 根据题目要求,最终返回「原字符串」和「压缩字符串」中长度较短的那个。

注意

在golang中,常规的字符串拼接方式,其性能较差,例如:“大量使用切片表达式” 和 “+ 运算符”会频繁内存分配,最终导致性能较差。

所以 在 golang 中,有大量字符串拼接的场景下,不建议直接使用 “+” 运算符来拼接字符串,以避免频繁的内存分配问题。

我们在以上思路的基础上做性能优化:

  • 使用byte数组:提前预估好容量大小,例如 方法2
  • 使用 strings.Builder:例如 方法3

string类型的 原理解析

  • 在底层,string类型的值会被存储在连续内存空间中(byte类型的字节数组)。而大量使用切片表达式和“+”运算符会导致频繁内存分配。
  • 因此,这些对string的操作相当于对底层字节数组进行操作,会导致更多的内存重分配开销,影响性能。

时间复杂度:O(N)

其中 N 为输入字符串 S 长度。指针 i , j 皆完成一次字符串遍历,循环 N+N=2N 次,使用 O(N) 线性时间。

空间复杂度:O(N)

res 用于临时存储压缩结果。最差情况下(当原字符串的所有相邻字符都不同时,a→a1 一个变两个),压缩字符串的长度为 2N,占用 O(2N)=O(N) 大小的额外空间。

// 版本1 字符串拼接(性能不佳)
// 在底层,string的值会被存储在连续内存空间中(字节数组)。
// 大量使用切片表达式和“+”运算符会导致频繁内存分配。
// 因此,这些对string的操作相当于对底层字节数组进行操作,会导致更多的内存重分配开销,影响性能。
func compressString(S string) string {sLen := len(S)if sLen <= 1 {return S}res := ""i, j := 0, 1for ; j < sLen; j++ {if S[i] != S[j] {res += string(S[i]) + strconv.Itoa(j-i)i = j}if len(res) >= sLen {return S}}// 在for循环中,S末尾的结果集还未处理,这里需要追加上来res += string(S[i]) + strconv.Itoa(j-i)// 若“压缩”后的字符串没有变短,则返回原先的字符串if len(res) >= sLen {return S}return res
}// 版本2:使用byte数组优化
func compressString(S string) string {sLen := len(S)if sLen <= 1 {return S}// 数组提前预估容量,避免重分配res := make([]byte, 0, sLen)i, j := 0, 1for ; j < sLen; j++ {if S[i] != S[j] {res = append(res, S[i])res = append(res, []byte(strconv.Itoa(j-i))...)// 这两个append的操作要分开写,不支持合并一起写;后面同理// res = append(res, S[i], byte(strconv.Itoa(j-i))) // 错误i = j}if len(res) >= sLen {return S}}res = append(res, S[i])res = append(res, []byte(strconv.Itoa(j-i))...)// 若“压缩”后的字符串没有变短,则返回原先的字符串if len(res) >= sLen {return S}return string(res)
}// 版本3:使用go strings.Builder优化
func compressString(S string) string {sLen := len(S)if sLen <= 1 {return S}// res := ""var sb strings.Builderi, j := 0, 1for ; j < sLen; j++ {if S[i] != S[j] {sb.WriteByte(S[i])sb.WriteString(strconv.Itoa(j - i))// res += string(S[i]) + strconv.Itoa(j-i)i = j}}sb.WriteByte(S[i])sb.WriteString(strconv.Itoa(j - i))// res += string(S[i]) + strconv.Itoa(j-i)if sb.Len() >= sLen {return S}return sb.String()
}

这篇关于LeetCode 面试题 01.06. 字符串压缩(443. 压缩字符串)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/540342

相关文章

JSON字符串转成java的Map对象详细步骤

《JSON字符串转成java的Map对象详细步骤》:本文主要介绍如何将JSON字符串转换为Java对象的步骤,包括定义Element类、使用Jackson库解析JSON和添加依赖,文中通过代码介绍... 目录步骤 1: 定义 Element 类步骤 2: 使用 Jackson 库解析 jsON步骤 3: 添

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

python修改字符串值的三种方法

《python修改字符串值的三种方法》本文主要介绍了python修改字符串值的三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录第一种方法:第二种方法:第三种方法:在python中,字符串对象是不可变类型,所以我们没办法直接

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

C#中字符串分割的多种方式

《C#中字符串分割的多种方式》在C#编程语言中,字符串处理是日常开发中不可或缺的一部分,字符串分割是处理文本数据时常用的操作,它允许我们将一个长字符串分解成多个子字符串,本文给大家介绍了C#中字符串分... 目录1. 使用 string.Split2. 使用正则表达式 (Regex.Split)3. 使用

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

Qt实现文件的压缩和解压缩操作

《Qt实现文件的压缩和解压缩操作》这篇文章主要为大家详细介绍了如何使用Qt库中的QZipReader和QZipWriter实现文件的压缩和解压缩功能,文中的示例代码简洁易懂,需要的可以参考一下... 目录一、实现方式二、具体步骤1、在.pro文件中添加模块gui-private2、通过QObject方式创建

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c