316. 去除重复字母

发布时间 2023-03-22 21:11:52作者: zhangk1988

题目描述

给了一个字符串s,需要删除重复的字符。
要求是(1)每个字母只保留一次;(2)结果的字典序最小

f1-贪心+单调栈

基本分析

  1. 如果给定一个s,只能删除一个,怎么删可以使字典序最小?从左到右删除第一个s[i]>s[i+1]的值,比如456651,删除第二个6;987,删除9。
  2. 结合上面的思路,怎么能让字典序尽量的小?遍历字符串,用一个栈来进行维护,保证里面的字符单调递增
  3. 字符保留和单调递增有冲突,怎么维护?只剩一次的时候就不删了;之前出现过就pass。用vis记录栈中的元素访问情况;用cnt记录元素剩余的可用次数,pass掉或者弹出时,可用次数-1。

代码

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        vis = set()
        cnt = Counter(s)
        stk = []


        n = len(s)

        for i, ch in enumerate(s):
            if ch in vis:
                cnt[ch] -= 1
                continue
            while stk and s[stk[-1]] > ch:
                if cnt[s[stk[-1]]] == 1:
                    break
                else:
                    top = stk.pop()
                    vis.remove(s[top])
                    cnt[s[top]] -= 1
            stk.append(i)
            vis.add(ch)
        
        return "".join([s[i] for i in stk])

总结

  1. 单调栈的两个特性,下标递增+下标对应的内容有某种规律
  2. 结果可以在栈中,也可以只把栈当工具,结果在数组中
  3. 有矛盾的约数的时候,其中一个只是限制条件