单调栈——316. 去除重复字母(上)

137 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。

题目描述

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

示例 1:

输入: s = "bcabc"
输出: "abc"

思路分析

即使是知道这题用单调栈,也很难想到,因为如果是直接用单调栈做的话,应该会在遇到a是弹出cb,当s = “bcab”时就会返回ab,而这个示例的正确输出应该是bca。

所以我们需要保证不弹出相同字母中最后一次出现的字母。可以通过一个数组➕一个map来实现,从后往前遍历字符串,记录每一个字母倒数第几次出现。

具体实现

string removeDuplicateLetters(string s) {
        map<char, int> mp;
        int len = s.size();
        vector<int> arr(len);
        stack<int> stk;
        string res = "";
        for(int i = len - 1; i >= 0; i -- ){
            if(mp[s[i]] == 0){
                mp[s[i]] = 1;
            }else{
                mp[s[i]] = mp[s[i]] + 1;
            }
             arr[i] = mp[s[i]];
        }

        for(int i = 0; i < len; i++){
            while(!stk.empty() && s[i] < s[stk.top()]){
                int tmp = stk.top();
                if (arr[tmp] == 1){
                    break;
                }
                stk.pop();
            }
            stk.push(i);
        }
        int k = mp.size();
        while(!stk.empty()) {
            res = s[stk.top()] + res;
            stk.pop();
        }
        return res.substr(0, k);
    }

截屏2022-01-22 下午9.32.00.png

总结

然而只是过了一半的用例,单调栈加一点灵活的思路是对的,但是不弹出字母最后出现的一次应该是错的,如果按照我的思路,输入为“cdadabcc”应该会输出“adabcc”,正确答案应该是adbc。字母如果已经被使用了,即使不满足单调栈的单调性,也有可能不需要再加进去。因为退栈时最后一次出现的字母是不可以被弹出的。不过因为能力有限,具体条件并没有想出来。留给下期。