[LeetCode No.316] 去除重复字母

题目

题解

这道题,还真木有想出来
看了一下官方视频解答,讲的比较好

大致思路:
例如:
输入:s = "bcabc"
输出:"abc"

b->bc>bca(由于c比a字典序大,所以这次考虑可以把c弹出去,看到c在后面还会出现,所以可以弹出去)->ba->a(同理弹b)->ab->abc
可以看到,弹出的时候满足后进先出,所以可以基本确定这里需要使用“栈”结构。

确定使用栈后,可以这么来看,一开始b压入,c压入。当要压入a时,因为此时栈顶元素“c”比“a”字典序大。如若a能在c前面肯定总字典序要更小
那么这时候看“a”后面还有没有“c”,显然有,那么可以把“c”pop出去,再把“a”压入。
Tip:显然如果后续在字符串遇见已经在栈内的字符。我们可以直接跳过。 (因为如果他在栈顶。没必要。如果在栈内,栈内的“它”肯定前小后大,所以忽略)
https://leetcode-cn.com/problems/remove-duplicate-letters/solution/zhan-by-liweiwei1419/) 这个题解后四段更为详细

代码

public class Solution {
    public String removeDuplicateLetters(String s) {
        int [] visited = new int[26];              //已经存在于栈中 标志数组
        int [] lastIndex = new int[26];              //存在字符,最后一次在字符串出现的index

        for (int i = 0; i < s.length(); i++) {
        lastIndex[s.charAt(i)-'a'] = i;                  //记录所有存在字符,最后一次出现的index
        }

        Deque<Character> ans = new ArrayDeque<Character>();          //栈

        for (int i = 0; i < s.length(); i++) {
        if (visited[s.charAt(i)-'a'] == 1){               //如果栈中已经存在,忽略   
            continue;
        }
        while (!ans.isEmpty()&&ans.peekLast()>s.charAt(i)&&i<lastIndex[ans.peekLast()-'a']){       //如果栈顶元素比待加入的字符 字典序大 ,则看一下该栈顶元素在后面是否还会出现
            char top = ans.removeLast();          //移除栈顶元素      
            visited[top-'a'] = 0;                   //栈顶元素,置为栈中未出现
        }
        ans.addLast(s.charAt(i));                 //将字符串的待加入字符加入栈顶              
        visited[s.charAt(i)-'a'] = 1;                //标志为栈中已存在
        }

        StringBuilder stringBuilder = new StringBuilder();
        for (char c:ans){
            stringBuilder.append(c);
        }

        return stringBuilder.toString();                     
    }
}

StringBuffer和StringBuilder区别:https://segmentfault.com/a/1190000017909550
stack:栈 数据是后进先出(LIFO)
queue:队列 数据是先进先出(FIFO)
deque:双端队列 数据可以从两端进出

posted @ 2020-12-22 22:47  饼先生  阅读(64)  评论(0编辑  收藏  举报