LeetCode刷题系列 -- 316. 去除重复字母

给定一个字符串,需要移除重复的字母,使每个字母只出现一次,同时保证结果字符串的字典序最小。算法通过使用单调栈实现,遍历字符串,根据字典序和字符出现位置更新栈。当遇到字典序小的字符时,可能需要弹出栈顶字符以保持字典序。Java代码示例展示了具体实现。
摘要由CSDN通过智能技术生成

给你一个字符串 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 相同

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-duplicate-letters
 

思路:

1. 定义一个map, 遍历数组,key 为字符,value 为字符在数组中最后出现的位置。遍历字符串,并将字符最后出现的位置更新到 map 中
2. 定义一个堆栈 Stack,保证该堆栈为单调栈,即从栈底到栈顶的字符串满足最小字典序
3. 遍历字符串中的每一个字符:
   3.1)  当栈为空时,将当前字符压入Stack中
   3.2)  当栈不为空时
      3.2.1) 当前字符的字典序大于栈顶字符时,则将当前字符压入Stack
      3.2.2) 当前字符的字典序小于栈顶字符时,
           3.2.2.1) 若是栈顶字符最后出现的位置小于当前字符的 index  且栈中不存在当前字符(若是存在该字符,说明当前字符与栈顶字符已经满足最小字典序了),说明后面不再有栈顶字符了,此时将当前字符压入Stack中;
           3.2.2.2) 若是栈顶字符最后出现的位置大于当前字符的 index,说明后面还有栈顶字符,为了保证字典序最小,将栈顶字符弹出;
             并循环3.2.2.2 过程,直到Stack 为空或者 栈顶字符最后出现的位置小于当前字符的 index 终止循环

java代码:

class Solution {
    public String removeDuplicateLetters(String s) {
        // key 为字符,value 为字符在数组中最后出现的位置
        Map<Character, Integer> map = new HashMap<>();

        for (int index = 0; index < s.length(); index++) {
            map.put(s.charAt(index), index);
        }

        Stack<Character> stack = new Stack<>();

        for (int index = 0; index < s.length(); index++) {
            if (stack.isEmpty()) {
                stack.push(s.charAt(index));
            } else {
                // 当前字符的字典序大于栈顶字符时
                if (s.charAt(index) > stack.peek()) {
                    if (!stack.contains(s.charAt(index))) {
                        stack.push(s.charAt(index));
                    }
                } else {
                    // 当前字符的字典序小于栈顶字符时
                    while (!stack.isEmpty() &&s.charAt(index) < stack.peek() && !stack.contains(s.charAt(index))&& map.get(stack.peek()) > index) {
                        stack.pop();
                    }
                    if (stack.isEmpty()) {
                        stack.push(s.charAt(index));
                    } else if (!stack.contains(s.charAt(index))) {
                        stack.push(s.charAt(index));
                    }
                }
            }
        }

        Stack<Character> resultStack = new Stack<>();

        while (!stack.isEmpty()) {
            resultStack.push(stack.pop());
        }

        StringBuilder stringBuilder = new StringBuilder();

        while (!resultStack.isEmpty()) {
            stringBuilder.append(resultStack.pop());
        }
        return stringBuilder.toString();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值