316. 去除重复字母
Posted 炫云云
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了316. 去除重复字母相关的知识,希望对你有一定的参考价值。
316. 去除重复字母
题目描述
给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: "bcabc"
输出: "abc"
示例 2:
输入: "cbacdcbc"
输出: "acdb"
思路
与上面题目不同,这道题没有一个全局的删除次数 k k k。而是对于每一个在字符串 s s s 中出现的字母 c c c 都有一个 k k k 值。这个 k k k 是 c c c 出现次数 - 1。
沿用上面的知识的话,我们首先要做的就是计算每一个字符的 k k k,可以用一个字典来描述这种关系,其中 k e y key key 为 字符 c c c, v a l u e value value 为其出现的次数。
具体算法:
- 建立一个字典。其中 k e y key key 为 字符 c c c, v a l u e value value 为其出现的剩余次数。
- 从左往右遍历字符串,每次遍历到一个字符,其剩余出现次数 - 1.
- 在弹出栈顶字符时,如果字符串在后面的位置上再也没有这一字符,则不能弹出栈顶字符。剩余数量为 0 时,就不能弹出栈顶字符了。
- 是否丢弃的标准和上面题目类似。如果栈顶的元素字典序更大,那么我们选择丢弃栈顶的元素。
还记得上面题目的边界条件么?如果栈中剩下的元素大于 n − k n - k n−k,我们选择截取前 n − k n - k n−k 个数字。然而本题中的 k 是分散在各个字符中的,因此这种思路不可行的。
不过不必担心。由于题目是要求只出现一次。我们可以在遍历的时候简单地判断其是否在栈上即可。
class Solution:
def removeDuplicateLetters(self, s) -> int:
stack = []
remain_counter = collections.Counter(s)
for char in s:
# c不在res中时再考虑是否添加
if char not in stack:
while stack and stack[-1] > char and remain_counter[stack[-1]] >0:
stack.pop()
stack.append(char)
remain_counter[char] -= 1
return ''.join(stack)
s = "bcabc"
import collections
remain_counter = collections.Counter(s)
remain_counter
Counter({'b': 2, 'c': 2, 'a': 1})
复杂度分析
- 时间复杂度:由于判断当前字符是否在栈上存在需要 O ( N ) O(N) O(N) 的时间,因此总的时间复杂度就是 O ( N 2 ) O(N ^ 2) O(N2),其中 N N N 为字符串长度。
- 空间复杂度:我们使用了额外的栈来存储数字,因此空间复杂度为 O ( N ) O(N) O(N),其中 N N N 为字符串长度。
查询给定字符是否在一个序列中存在的方法。根本上来说,有两种可能:
- 有序序列: 可以二分法,时间复杂度大致是 O ( N ) O(N) O(N)。
- 无序序列: 可以使用遍历的方式,最坏的情况下时间复杂度为 O ( N ) O(N) O(N)。我们也可以使用空间换时间的方式,使用 N N N的空间 换取 O ( 1 ) O(1) O(1)的时间复杂度。
由于本题中的 stack 并不是有序的,因此我们的优化点考虑空间换时间。而由于每种字符仅可以出现一次,这里使用 hashset 即可。
class Solution:
def removeDuplicateLetters(self, s) -> int:
stack = []
seen = set()
remain_counter = collections.Counter(s)
for char in s:
if char not in seen: # 空间换时间
while stack and stack[-1] > char and remain_counter[stack[-1]] >0:
seen.discard(stack.pop()) # discard() 函数是用来删除元素的
seen.add(char)
stack.append(char)
remain_counter[char] -= 1
return ''.join(stack)
复杂度分析
- 时间复杂度: O ( N ) O(N) O(N),其中 N N N 为字符串长度。
- 空间复杂度:我们使用了额外的栈和 hashset,因此空间复杂度为 O ( N ) O(N) O(N),其中 N N N 为字符串长度。
参考
以上是关于316. 去除重复字母的主要内容,如果未能解决你的问题,请参考以下文章
2021-08-31:去除重复字母。给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。力扣316。