去除重复字母
描述
中等
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
注意:该题与 leetcode 1081相同
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
- 1 <= s.length <= 104
- s 由小写英文字母组成
解题
一开始以为是直接去重,然后返回字典序最小的排列方式,按照ASCII码排序,然后错了
关键是不能打乱字符的相对位置
按照示例2
s = 'cbacdcbc'
设置一个栈来保存最后结果的组成字符
然后依次扫描每个字符
-
扫描到
c
时,直接入栈 -
扫描到
b
时,由于b
后面仍然有c
,而且b
的ASCII码比c
小,所以当前栈中的c
可以删除,当后面碰到c
时可以再将c
入栈 -
扫描到
a
时,由于a
后面仍然有b
,而且a
的ASCII码比b
小,所以当前栈中的b
可以删除,当后面碰到b
时可以再将b
入栈 -
扫描到
c
时,c
的ASCII码比a
大,直接入栈 -
扫描到
d
时,d
的ASCII码比c
大,直接入栈 -
扫描到
c
时,由于栈中已经存在了c
,所以不需要任何处理 -
扫描到
b
时,由于s
中只有一个d
,必须用上,所以虽然b
的ASCII码比d
小,也只能入栈 -
最后栈中的字符为
[a,c,d,b]
在代码中使用字典记录每个字符出现的最后位置
来判断当前扫描到的字符后面是否存在栈中的字符
从而决定能否将栈中的字符弹出
class Solution:
def removeDuplicateLetters(self, s: str) -> str:
last_pos = {} # 记录每个字符最后出现的位置
for i, c in enumerate(s):
last_pos[c] = i
stack = []
for i, c in enumerate(s):
if c in stack: # 当当前字符在栈中出现时,跳过本次循环
continue
while len(stack) > 0 and stack[-1] > c and last_pos[stack[-1]] > i:
# 当当前字符的ASCII码大于栈中最后一个字符,同时,栈中最后一个字符在之后还会出现时,删除该字符
stack.pop()
stack.append(c) # 入栈
return ''.join(stack)