力扣-316. 去除重复字母

1.题目

题目地址(316. 去除重复字母 - 力扣(LeetCode))

https://leetcode.cn/problems/remove-duplicate-letters/

题目描述

给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的

最小(要求不能打乱其他字符的相对位置)。

 

示例 1:

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

示例 2:

输入:s = "cbacdcbc"
输出:"acdb"

 

提示:

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

 

注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同

2.题解

2.1 单调栈+

思路

代码

  • 语言支持:C++

C++ Code:


class Solution {
public:
    string removeDuplicateLetters(string s) {
        vector<int> nums(26), vis(26);
        // 初始化各元素初始个数
        for(char ch : s){
            nums[ch - 'a']++;
        }

        // 贪心+单调栈解决字符串去重问题
        string stk; // 跳出固有思维, 单调栈是一种算法思维,并不一定非要使用栈
        for(char ch : s){
            // 如果当前字符尚未被访问
            if(!vis[ch - 'a']){
                // 保证单调栈从栈顶到栈底递减(小的字符在栈底,保证字节序小), 当前字符小于栈顶就弹出栈顶
                while(!stk.empty() && ch < stk.back()){
                    // 如果剩余字符数量足够,就弹出
                    if(nums[stk.back() - 'a']){
                        vis[stk.back() - 'a'] = 0; // 更新为未访问状态
                        stk.pop_back(); // 弹出
                    } else{
                        break;
                    }
                }
                // 找到当前字符应有的入栈位置
                stk.push_back(ch);
                vis[ch - 'a'] = 1; // 更新访问标志    
            }
            // 如果当前字符访问过则不入栈, 但还是要更细剩余数量,所以将两种情况合二为一
            nums[ch - 'a']--;
        }
        return stk;
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)
posted @ 2024-05-18 11:43  DawnTraveler  阅读(20)  评论(0编辑  收藏  举报