算法随笔_30: 去除重复字母

server/2025/2/2 3:03:47/

上一篇:算法随笔_29:最大宽度坡_方法3-CSDN博客

=====

题目描述如下:

给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

示例 1:

输入:s = "bcabc"
输出"abc"

=====

算法思路:

首先我们考虑第一个条件: 如何去掉字符串中重复的字母?这个比较简单。我们可以新开辟一个同样长度的新数组s_new来存储最后的结果。然后我们从左往右遍历原数组,依次把字符放入新数组s_new中。并判断即将放入的字符在新数组当中是否已经出现,如果出现,则不放入字符。最终得到的就是去掉重复字符之后的新的字符串。在代码实现的时候可能会有一些细节需要考虑,比如说,s_new数组后面可能会出现未填满的情况,但这属于细节问题,在代码实现中可以用各种办法解决它,同时也不会影响时间复杂度。

现在让我们来看第二个条件: 最终答案需要取字典序最小的字符串。比如,示例1中有两种可能的符合去重条件的答案: bca,  abc。同样都是去掉重复字符之后的字符串,但字典序最小的字符串是abc。

因此,在上面的算法中,当发现放入的字符比如: c,在新数组中已经出现时,我们需要一个算法来判断如何进行重复字符的取舍问题。是保留已经在数组中的字符c,还是需要删除它,放入后面的字符c。

我们拿上面的例子做进一步的分析。bcabc,我们从左向右枚举原字符串,当枚举到第二个b时,如果删除最后一个b,那么字符串就变成bca。删除第一个b,字符串就变成了cab。我们发现只要b的后面的字符是大于b的,肯定要删除第二次出现的重复字母。因为如果删除了第一次出现的字符b,字符c就前移一位,不管后面的字符串是什么样的,以字符c开始引领的字符串必然大于以字符b开始引领的同样长度的字符串。

与上面的情况类似,如果b的后面的字符是小于b的字符,那需要删除第一个字符b。比如bab,最后的结果应该是ab。

因此,我们发现的特征就是:

如果s[i]>s[i+1],且s[i]这个字符出现2次及以上时,我们需要删除这个字符s[i]。

此时注意一下,当删除s[i]之后,s[i+1]移到了s[i]这个位置,新的排列仍然需要保持这个特征。即,如果s[i-1]仍然大于s[i+1],且s[i-1]这个字符出现2次及以上时,我们仍需要删除这个字符s[i-1],s[i+1]需要继续前移。

还是用上面的例子说明,当我们尝试放入s_new时,有如下步骤:

- 放入b

- 因为c大于b,所以放入c

- 因为a小于c,且c出现2次,删除c

- a继续和b比较,a小于b,且b出现2次,删除b。前面已经没有可以删除的字符,放入a。

- 因为b大于a,所以放入b

- 因为c大于b,所以放入c,至此完成。

这里有一些细节还需要说明一下。

1. 假如原字符很长,abc后面还有其他字符,且abc每个字符后面都还出现多次以上。仍然需要按照上面的规律来放入s_new。

2.  只出现1次的字符,必须保留。比如上面的例子,如果没有第二次出现的字符c。需要依次放入bca,然后舍弃第二个b。因为字符c不能删除,所以字符a就无需依次和前面的比较了。

3.  即将放入的字符如果在s_new中已经存在,则不能放入。

我们发现s_new中的字符有个特点,除了那些只出现1次的字符,出现2次及以上的字符都是按字典序增大的,然后碰到小于的字符在一个一个删除。这很像一个数据结构。先递增入栈,在依据条件出栈。

经过上面一系列的分析,我们大体了解了整个的算法思路。下面我们来给出详细的算法:

1. 初始ch2cnt数组,共26个元素。我们用每个字母与字母a的ascii码的差值来做为数组的索引。初始元素值为0。遍历一遍原字符串,相同字母每出现一次,ch2cnt相应的元素值加1。统计出每个字母出现的次数。

2.  初始putted数组,也是26个元素。用每个字母与字母a的ascii码的差值来做为数组的索引。元素值为1表示此字母在s_new中已经存在,0表示不存在。然后把原字符串s中第一个字符在putted中对应的元素置为1。设置此数组的目的是为了更高效的查询s_new中已存在的字符,仅有O(1) 的时间复杂度。

3. 设s_new数组为最终的字符串数组。初始化时放入原字符串s的第一个字符。

4.  从第二个字符开始,从左向右枚举原字符串s。

5.  通过putted,判断当前字符s[i]是否在s_new中已经存在。如果存在,不放入s_new,且在ch2cnt中对应字符的次数减1。转到步骤4继续。如果不存在,转到下一步。

5.  从右往左枚举s_new数组,让s[i]依次与s_new数组的字符j比较,如果s[i]<=s_new[j]且字符j出现的次数大于1,我们去掉s_new的最后一个字符。循环步骤5,直到退出循环,然后我们把s[i]放入s_new。

其他一些细节详见代码。下面是代码实现:

class Solution(object):def removeDuplicateLetters(self, s):""":type s: str:rtype: str"""ord_a=ord('a')ch2cnt=[]putted=[]for i in range(26):ch2cnt.append(0)putted.append(0)for ch in s:ch2cnt[ord(ch)-ord_a]+=1s_len=len(s)s_new=[s[0]]putted[ord(s[0])-ord_a]=1for i in range(1,s_len):ord_si=ord(s[i])-ord_aif putted[ord_si]==1:ch2cnt[ord_si]-=1continuej=len(s_new)-1while j>=0 and s[i]<=s_new[j] and ch2cnt[ord(s_new[j])-ord_a]>1:ch2cnt[ord(s_new[j])-ord_a]-=1putted[ord(s_new[j])-ord_a]=0s_new.pop()j-=1s_new.append(s[i])putted[ord_si]=1res=''.join(s_new)return res

算法的时间复杂度为O(n) 。


http://www.ppmy.cn/server/164237.html

相关文章

汽车网络信息安全-ISO/SAE 21434解析(中)

目录 第七章-分布式网络安全活动 1. 供应商能力评估 2. 报价 3. 网络安全职责界定 第八章-持续的网络安全活动 1. 网路安全监控 2. 网络安全事件评估 3. 漏洞分析 4. 漏洞管理 第九章-概念阶段 1. 对象定义 2. 网路安全目标 3. 网络安全概念 第十章 - 产品开发 第十…

Docker 仓库管理

Docker 仓库管理 引言 随着容器技术的兴起,Docker 已成为最流行的容器化平台之一。在Docker的生态系统中,仓库(Repository)是至关重要的组成部分。一个有效的仓库管理策略可以帮助开发者更高效地构建、测试、部署和管理容器应用。本文将深入探讨Docker仓库管理的相关知识…

【基于SprintBoot+Mybatis+Mysql】电脑商城项目之用户注册

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;项目基本介绍 &#x1f6a6;项…

高级java每日一道面试题-2025年01月24日-框架篇[SpringMVC篇]-SpringMVC常用的注解有哪些?

如果有遗漏,评论区告诉我进行补充 面试官: SpringMVC常用的注解有哪些? 我回答: 一、核心注解详解 1. Controller 作用&#xff1a;将一个普通的Java类标记为处理请求的控制器。 应用场景&#xff1a;在Spring MVC中起到了路由请求和处理业务逻辑的作用&#xff0c;并注册…

春节假期旅游热潮下,景区医疗安全如何全面升级?

随着旅游业的不断繁荣&#xff0c;春节假期期间&#xff0c;各大景区再次迎来了游客的高峰期。面对如此庞大的客流量&#xff0c;景区不仅要在服务接待上下功夫&#xff0c;更要将医疗安全保障工作提升到新的高度。那么&#xff0c;在旅游高峰期&#xff0c;景区应该如何有效应…

第04章 08 VTK Filter 的组成与运作原理

在 VTK&#xff08;Visualization Toolkit&#xff09;中&#xff0c;Filter 是处理和转换数据的核心组件。它们用于对输入数据进行各种操作&#xff0c;如几何变换、数据过滤、属性计算等&#xff0c;并生成新的输出数据。Filter 的组成与运作原理是 VTK 数据处理流程的关键。…

穿心莲内酯(andrographolide)生物合成CYP72-文献精读106

Two CYP72 enzymes function as Ent-labdane hydroxylases in the biosynthesis of andrographolide in Andrographis paniculata 两种CYP72酶在穿心莲&#xff08;Andrographis paniculata&#xff09;中作为Ent-labdane羟化酶&#xff0c;在穿心莲内酯&#xff08;andrograp…

2025年1月22日(网络编程)

系统信息&#xff1a; ubuntu 16.04LTS Raspberry Pi Zero 2W 系统版本&#xff1a; 2024-10-22-raspios-bullseye-armhf Python 版本&#xff1a;Python 3.9.2 已安装 pip3 支持拍摄 1080p 30 (1092*1080), 720p 60 (1280*720), 60/90 (640*480) 已安装 vim 已安装 git 学习…