316. 去除重复字母/单调栈+字典序【leetcode】

该文章介绍了一种利用单调栈解决字符串中去除重复字母的问题,要求保持字典序最小且不改变其他字符的相对位置。通过遍历字符串,结合单调栈和额外的计数及存在数组,确保每次入栈的字符都是当前未出现且能保持栈内顺序递增的字符。最终得到的结果是字典序最小的字符串。
摘要由CSDN通过智能技术生成

316. 去除重复字母

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

示例 1:
输入:s = “bcabc”
输出:“abc”

示例 2:
输入:s = “cbacdcbc”
输出:“acdb”

提示:
1 <= s.length <= 104
s 由小写英文字母组成

字典序

首先讲一讲这一题的字典序,字符串的字典序,就是从字符串的第一位开始比较,如果第一位ASCII小则字典序就小,如果第一位相同,则第二位的字典序谁小就小,以此类推。故这一题应该尽可能让字典序小的靠前。

单调栈

一直以为这一题是要最小字典序是用单调队列,但是谁知道是用单调栈。
首先要想到:单调递增的字符串就是最小的

以bcabc为例,先将b推入栈,再将c推入栈,是递增的可以直接推,然后到a,而ca肯定是大于ac的,所以如果后面还有c的话会更小,就想到可以用数组记录各个字母的次数,再用一个数组记录字母是否在栈中,后面还有c,所以可以把c推出栈,再看b,同样的过程,也可以把b推出栈,再将b和c分别推入栈。
故过程是:b入,c入,c出,b出
后入先出,符合栈的特征。

代码

class Solution {
public:                    
    string removeDuplicateLetters(string s) 
    {
       vector<int>num(26),exi(26,0);
       string sub="";
       stack<char>stk;
       for(int i=0;i<s.size();i++) num[s[i]-'a']++;
       for(int i=0;i<s.size();i++)
       {
          if(exi[s[i]-'a']==1)
          {
             num[s[i]-'a']--;
             continue;
          }//栈中存在的就直接不考虑了,注意按照例子b刚开始就在栈中,
          //那后面的b怎么办,后面会有个a而把前面的bpop出去的。
          if(!stk.empty()&&s[i]>stk.top()&&exi[s[i]-'a']==0)
          {
               stk.push(s[i]);
               exi[s[i]-'a']=1;
               num[s[i]-'a']--;                                                
          }
          else
          {
            while(!stk.empty()&&s[i]<stk.top())
            {
                if(num[stk.top()-'a']>0) 
                {
                    exi[stk.top()-'a']=0;
                    stk.pop();
                }
                else break;
                //这个必不可少,不然如果满足while不满足if就一直循环出不去了
            }
            if(exi[s[i]-'a']==0)
            {
                stk.push(s[i]);
                num[stk.top()-'a']--;
                exi[stk.top()-'a']=1;
            }
        }
    }
    while(stk.size()!=0)
    {
        sub=stk.top()+sub;
        stk.pop();
    }
    s=sub;
    return s;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值