316. Remove Duplicate Letters

本文介绍了一种高效算法,用于从字符串中移除重复字符,并保持剩余字符的原始顺序不变的同时进行排序。通过使用哈希表记录字符频率及访问状态,确保了处理过程的准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题让我们移除重复字母,使得每个字符只能出现一次,而且结果要按字母顺序排,前提是不能打乱其原本的相对位置。

这道题我一开始用的dfs,也就是碰到重复的字母,要么把这个加进去,把前面重复的那个删掉,要么不把这个加进去,保留前面那个。但是超时……代码如下:

class Solution {
public:
    string removeDuplicateLetters(string s) {
        set<string> res;
        helper(s, 1, s.substr(0, 1), res);
        return *res.begin();
    }
    void helper(string s, int start, string out, set<string>& res){
        if(start >= s.size())
            res.insert(out);
        for(int right = start; right < s.size(); ++right){
            if(find(out.begin(), out.end(), s[right]) == out.end()){
                out.push_back(s[right]);
                //helper(s, right+1, out, res);
            }else{
                helper(s, right+1, out, res);//不要right这个位置的字符
                out.erase(find(out.begin(), out.end(), s[right]));
                out.push_back(s[right]);
                helper(s, right+1, out, res);//要right这个位置的字符,把前面的删掉
            }
        }
        res.insert(out);
    }
};

看了大神的代码,发现自己确实想不到,这道题应该这样做:

建立一个数组或者哈希表,遍历字符串,记录每个字母出现的次数。再定义一个数组visit表示每个字符是否访问过

遍历字符串,遇到一个字符s[i],如果这个字符访问过,跳过。如果这个字符没有访问过,那么比较res里面最后加进去的这个字符res.back(),如果s[i]<res.back(),而且res.back()这个字符在m里还有多余的,说明res.back()可以先删掉,在后面加,直到不满足s[i]<res.back()或者m[res.back()]>0,就把s[i]放在这个位置。

让我想了半天的是这个visit数组,为什么visit[i]为1的时候要跳过呢,因为visit[i] = 1的时候,说明截止到目前为止,s[i]这个字母已经放好了。所以visit[i]不能说是访问过,而是表示是否已经放好了。如果一个字符本来放好了又被换下来了,那么他的visit会是0;

这种与重复字符有关的题,可以想哈希表的方法记录原字符串中每个字符出现的次数,然后再按照每个题目不同的要求往下做,这种思路已经遇到过很多次。

class Solution {
public:
    string removeDuplicateLetters(string s) {
        vector<int> m(256, 0);
        vector<int> visit(256, 0);
        string res = "0";
        for(auto a : s){
            m[a]++;
        }
        for(auto a : s){
            --m[a];
            if(visit[a]) continue;
            while(a < res.back() && m[res.back()]){
                visit[res.back()] = 0;
                res.pop_back();
            }
            res.push_back(a);
            visit[a] = 1;
        }
        return res.substr(1);
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值