316. Remove Duplicate Letters (贪心)

题目描述:

说是要删除重复的字母,系统只会给小写字母,然后所选的删除策略会使字典序较小的字母尽可能排在前面,比如'a'排在'b'前面。

思路:

首先一个大体策略:先把当前字符前面的那些字符进行判断,如果当前字符字典序 < 前面字符的字典序,那么如果前面字符在当前字符的后面也出现了,那么可以删除前面的字符。

我们这里用一种数据结构会比较好处理——栈

具体思路:

  • 先用一个int数组记录每个字母出现次数(下标用字母和a字母的差值)(节省判断重复字符的时间)
  • 第一个元素直接入栈初始化
  • 遍历到的元素和栈顶元素作对比,若遍历到的元素 > 栈顶元素 && 栈中没有和遍历到的元素相同元素:遍历到的元素入栈
  • 遍历到的元素和栈顶元素作对比,若遍历到的元素 < 栈顶元素:判断是否后面有重复的元素,有的话删除栈顶,继续往前判断,知道栈中出现比当前元素大的元素或栈中元素在后面没有重复时将当前元素入栈
  • 注意点:遍历过的元素要将其对应的字母出现次数 - 1、用过的字母记录下来

代码:

class Solution {
public:
    string removeDuplicateLetters(string s) {
        //栈逐个存储
        //"bcabc"
        //[ b ]
        //[ b c ]
        //[ b ]
        //[ a ]
        //出现字典序更小的字符,判断前面的字符有没有在后面出现,出现的话出栈
        stack<char> strStack;
        //记录字母都出现多少次就不用再去扫描了
        int letter[50];
        //记录用到了那些字母
        int useLetter[50];
        memset(letter, 0, sizeof(letter));
        memset(useLetter, 0, sizeof(useLetter));
        //字符串长度
        int strLen = s.length();
        if(strLen == 0) return "";
        //记录字母出现次数
        for(int i = 0; i < strLen; i++){
            letter[s[i] - 'a'] += 1;
        }
        //第一个元素无论如何都要入
        strStack.push(s[0]);
        useLetter[s[0] - 'a'] += 1;
        letter[s[0] - 'a'] -= 1;
        for(int i = 1; i < strLen; i++){
            letter[s[i] - 'a'] -= 1;
            //判断前面有没有用过
            if(useLetter[s[i] - 'a'] <= 0) {
                //栈顶就是前面一个
                //如果字典序比前面小的话要考虑前面的需不需要删掉,如果大的话直接加嘛,前面部分已经考虑好了
                if(s[i]-'a' > strStack.top()-'a'){
                    strStack.push(s[i]);
                    useLetter[s[i] - 'a'] += 1;
                }else if(s[i] - 'a' < strStack.top() - 'a'){
                    while(!strStack.empty()){
                        //往前一直扫到一定条件结束
                        if(s[i] - 'a' < strStack.top() - 'a'){
                            if(letter[strStack.top() - 'a'] > 0){
                                // //记录哪个已经用过了
                                useLetter[strStack.top() - 'a'] -= 1;
                                //后面有相同的就可以pop出来
                                strStack.pop();
                            }else{
                                //不重复情况
                                break;
                            }
                        }else break;
                    }
                    //记得把当前的元素塞进去
                    strStack.push(s[i]);
                    useLetter[s[i] - 'a'] += 1;
                }
                //等于情况不用变嘛,前面那个出来这个进去等于没操作
            }
            
        }
        vector<char> tmp;
        while(!strStack.empty()){
            tmp.push_back(strStack.top());
            strStack.pop();
        }
        string result ="";
        for(int i = tmp.size()-1; i >= 0; i--) result += tmp[i];
        return result;
    }
};

讲道理A出去的时候我都惊了出现了个0ms,测试数据长度太小了咩

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_我走路带风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值