【LeetCode】316.去除重复字母

题目链接

316. 去除重复字母

题目描述

解题思路

单调栈的应用

本题的解决可以分为两个过程:

(1) 去重,使得所有元素只出现一次。

(2) 返回字典序最小

先忽略过程2,利用栈这个数据结构实现去重。去重的原理就是利用isUsed数组标记该元素是否在栈中出现,如果是则跳过,否则在栈中加入该元素。

如何让栈中存在的字符串组成的字典序最小呢?

这就是单调栈的应用,但是必须要注意的一点就是:当栈顶元素大于要push进去的元素时

stk.peek() > c 时才会 pop 元素,其实这时候应该分两种情况:

  • 如果 st.peek() 这个字符之后还会出现,那么可以把它 pop 出去,反正后面还有嘛,后面再 push 到栈里,刚好符合字典序的要求。

  • 如果 st.peek() 这个字符之后不会出现了,前面也说了栈中不会存在重复的元素,那么就不能把它 pop 出去,否则你就永远失去了这个字符。

AC代码

//1.利用栈实现去重
class Solution {
    public String removeDuplicateLetters(String s) {
        Stack<Character> st = new Stack();
        StringBuffer ans = new StringBuffer();
        boolean isUsed[] = new boolean[26];
        char[] sChar = s.toCharArray();
        int charCount[] = new int[26];
        for(char i : sChar){
            if(isUsed[i-'a']) continue;
            st.push(i);
            isUsed[i-'a'] = true;
        }
        while(!st.isEmpty()) ans.append(st.pop());
        return ans.reverse().toString();
    }
}
//2.完整代码
class Solution {
    public String removeDuplicateLetters(String s) {
        Stack<Character> st = new Stack();
        StringBuffer ans = new StringBuffer();
        //根据isUsed数组实现栈中元素去重
        boolean isUsed[] = new boolean[26];
        char[] sChar = s.toCharArray();
        int charCount[] = new int[26];
        //记录每个字符出现的次数
        for(char i : sChar) charCount[i-'a']++;
        for(char i : sChar){
            charCount[i-'a']--;
            if(isUsed[i-'a']) continue;
            while(!st.isEmpty() && st.peek() > i && charCount[st.peek()-'a'] > 0){
                isUsed[st.peek()-'a'] = false;
                st.pop();
            }
            st.push(i);
            isUsed[i-'a'] = true;
        }
        while(!st.isEmpty()) ans.append(st.pop());
        return ans.reverse().toString();
    }
}
原文地址:https://www.cnblogs.com/XDU-Lakers/p/14163428.html