leetcode 316. Remove Duplicate Letters(删除重复的字母)

本文介绍了一种高效算法,用于去除字符串中的重复字符,并确保输出的字符串在字典序上是最小的。通过两次遍历字符串,第一次统计字符频率,第二次构建结果字符串,算法巧妙地实现了目标。

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

Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.

Example 1:

Input: “bcabc”
Output: “abc”
Example 2:

Input: “cbacdcbc”
Output: “acdb”

给出一个字符串,让output出unique的字符,
而且字符的顺序:比如上例的“bcabc",当前面和后面都有bc的时候,因为a在字符顺序上位于bc前面,所以只输出后面的bc,unique输出是abc
第二个例子,c的字母顺序在d前面,尽管后面有c,也是输出cd,全体是acdb

思路:
先读一遍字符串,记下每个字符出现了几次,记在count数组中。
字母只有26个,直接用数组即可,不需要HashMap。

然后再读一遍,这次要把字母保存到result字符串中。同时用过的字母它对应的次数要-1。
我们要保证result中字母是排好序的,怎么做到呢?就是每次来一个新字母的时候都要把前面比它大的删掉,当然如果前面比它大的仅此一个(用到了出现次数),后面没了,就不能删了。

如果result为空,直接把字母append进去,同时用一个visited数组标记这个字母已经在result里面了,如果下次s中出现了同样的,就不需要再处理了,直接跳过。

因为result中是已经按要求排好序的,所以不必纠结每次都要遍历一遍result,都要去和当前s的字母比较,只需要把result最后的字母(最大的)和s当前字母比,如果比s[i]小,就直接append s[i],不需再比。

如果result最后的字母比s[i]大,是不是就要删除?不一定,因为如果后面没有这个字母了怎么办,不就少一个字母了。
这时count数组起作用了,它记录了每个字母出现的次数,如果次数为0了,说明后面没有了,不能删。

如果后面还有,那么删掉,再取 下一个result的最后字母,直到不满足条件或result为空为止。

    public String removeDuplicateLetters(String s) {
        int[] cnt = new int[26];
        int n = s.length();
        boolean[] visited = new boolean[26];
        StringBuilder result = new StringBuilder();
        
        for(int i = 0; i < n; i ++) {
            cnt[s.charAt(i) - 'a'] ++;
        }
        
        for(int i = 0; i < n; i ++) {
            int len = result.length();
            char sc = s.charAt(i);
            
            cnt[sc - 'a'] --;  //用过字母的次数-1
            
            if(visited[sc - 'a']) continue;  //已经在result里面的不需要再处理
            
            while(len > 0 && result.charAt(len-1) > sc && 
                  cnt[result.charAt(len-1) - 'a'] > 0) {  
                visited[result.charAt(len-1) - 'a'] = false; //删掉了,result中没有了,要在删掉之前,因为result.length会变
                result.deleteCharAt(len - 1);
                len --;
            }
            result.append(sc);
            visited[sc - 'a'] = true;
        }
        
        return result.toString();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝羽飞鸟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值