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

示例 1:

输入: “bcabc”
输出: "ab
c"
示例 2:

输入: “cbacdcbc”
输出: "acdb"


题目要求去除字符串中重复的字母,即使得字符串中的每个字母只能出现一次。同时保证最后的字符串的字典序最小,且最后字符串中字母间相对的前后顺序不能改变

因此,我们需要遍历字符串,同时使用栈来保存当前已经遍历的字符:

  • 如果当前字符不在栈中,那么将其入栈
  • 如果当前字符已经在栈中,说明当前字符是重复的,继续往后遍历

经过上述的流程,最终栈中的字符肯定是不重复的,且字符间的相对顺序可以保证,但是却可能不是字典序最小的。例如,题目给出的实例1bcabc,算法的执行流程为:



python中去除重复元素 python去除重复字母_字符串


而正确的结果应该是abc。可以发现,当a入栈时,bc字典序都比a大,而且它们在剩下的字符串中还存在。所以,当遍历到某个字符在栈中不存在时:

  • 如果当前字符比栈顶字符字典序小,而且栈顶字符在剩下的字符串中依然存在,那么栈顶元素应该出栈
  • 直到栈为空或者栈顶元素字典序比当前字符小,将当前字符入栈

判断栈顶字符在剩下的字符串中是否存在,可以使用哈希表统计原始字符串中各不重复字符和出现的次数,也可以使用in来判断,但是哈希表的判断方式时间复杂度更低。

所以,完整的代码如下:

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        if not s: return ""

        d = Counter(s)
        stack = []
        for i in list(s):
        	# 每访问一个字符,对应计数 - 1
            d[i] -= 1
            if i in stack:
               continue
            else:
                while stack and i < stack[-1] and d[stack[-1]] > 0:
                    stack.pop()
            
                stack.append(i)

        return str(''.join(stack))