LeetCode316. 去除重复字母

力扣

 

解题思路:

要想使结果的字典序最小,就应该尽可能地将小的元素留在前面。

1. 如果stk栈顶的元素大于当前遍历到的元素,根据上述原则,则应该在条件允许的情况下回避这一情况,根据题目要求(去重),只有在后续还有这个栈顶元素的情况下才能将这个栈顶元素去掉(减少一个逆序)。如果后续没有这个栈顶元素,则只能将它保留在这儿,即使它大于它的下一个元素。

2. 这样一来,stk中保存的两两相邻元素要么是顺序的(前一个小于后一个)要么是逆序的(前一个大于后一个,虽有违背最小排列,但由于没有后续相同元素可以替换,只能这样将就)。

3. 由2)可知如果当前元素存在于stk中,则说明stk中的这个元素已经是顺序的了(^-^),所以应该在循环中先判断这一情况,直接跳过当前元素。

4. 同时,当根据条件去掉一个栈顶元素时,新的栈顶元素可能也大于当前元素,所以应该继续判断新的栈顶元素和当前元素的关系,用一个while循环,直到出现一个不满足循环条件的栈顶元素(要么小于当前元素,要么大于当前元素但后续又无与之相同的元素来替代)。

作者:fu-guang
链接:https://leetcode-cn.com/problems/remove-duplicate-letters/solution/c-0ms-ji-bai-100jian-ming-dai-ma-chao-xiang-xi-jie/
来源:力扣(LeetCode)

                         

 补充:

这里可以使用 string 来 代替 stack ,最后的结果可以直接返回。

class Solution {
public:
    string removeDuplicateLetters(string s) 
    {
      vector<int> vis(26 , 0), num(26 , 0);//num用于统计次数 vis用于判断是否使用过
        for (char ch : s)
        {
            num[ch - 'a']++;
        }

        int retsize = 0; //实际应该返回的字符个数
        for(int i = 0 ; i <26 ;++i)
        {
            if(num[i])
            ++retsize;
        }

        
        stack<char> st; //利用栈模拟
        st.push('A');
        for(char ch : s)
        {
            if(vis[ch - 'a'] == 0)//这个字符没有用过
            {
                while(st.top() > ch) //这个字符大小 < 栈顶元素,为了保证字典序需要弹出栈顶
                {
                    if(num[st.top() - 'a'] > 0 ) //回退,弹出栈顶元素
                    {
                      vis[st.top() - 'a'] = 0;//将弹出的元素设置为未使用
                      st.pop();
                    }
                    else //只有一个字符,直接入栈,即使这个元素 无法满足升序要求
                    {
                        break;
                    }

                    
                }
                vis[ch - 'a'] = 1;//标记为已使用
                st.push(ch);
            }
            num[ch - 'a']--; //可用次数--
        }
  


         string ret;
         ret.resize(retsize);
         for(int i = retsize-1 ; i >= 0 ;--i)
        {
          ret[i] = st.top();
          st.pop();
        }

        return ret;


        // 2.
        // string stk;
        // for (char ch : s) 
        // {
        //     if (!vis[ch - 'a']) 
        //     {
        //         while (!stk.empty() && stk.back() > ch) 
        //         {
        //             if (num[stk.back() - 'a'] > 0) 
        //             {
        //                 vis[stk.back() - 'a'] = 0;
        //                 stk.pop_back();
        //             } else 
        //             {
        //                 break;
        //             }
        //         }
        //         vis[ch - 'a'] = 1;
        //         stk.push_back(ch);
        //     }
        //     num[ch - 'a'] -= 1;
        // }
        
        // return stk;

    }

 
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值