【LeetCode: 316. 去除重复字母 + 栈 + 哈希表】

|-----------|
| 🚀 算法题 🚀 |

🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀
🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🌲 恭喜你发现一枚宝藏博主,赶快收入囊中吧🌻
🌲 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯

|-----------|
| 🚀 算法题 🚀 |

🍔 目录

    • [🚩 题目链接](#🚩 题目链接)
    • [⛲ 题目描述](#⛲ 题目描述)
    • [🌟 求解思路&实现代码&运行结果](#🌟 求解思路&实现代码&运行结果)
      • [⚡ 栈 + 哈希表](#⚡ 栈 + 哈希表)
        • [🥦 求解思路](#🥦 求解思路)
        • [🥦 实现代码](#🥦 实现代码)
        • [🥦 运行结果](#🥦 运行结果)
    • [💬 共勉](#💬 共勉)

🚩 题目链接

⛲ 题目描述

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

🌟 求解思路&实现代码&运行结果


⚡ 栈 + 哈希表

🥦 求解思路
  1. 数据结构初始化
    创建一个HashMap类型的remainCounter用于统计每个字符在后续字符串中剩余的出现次数,通过循环字符串s中的字符来初始化其计数。同时创建一个Stack类型的stack用于存储最终结果字符,一个HashSet类型的seen用于记录已经添加到栈中的字符。
  2. 遍历输入字符串
  • 对于字符串s中的每个字符c,先更新其在remainCounter中的剩余出现次数。
  • 如果字符c已经在seen集合中(意味着已经处理过了),则跳过本次循环,继续处理下一个字符。
  • 接着,和 Python 代码类似的逻辑,如果栈不为空,当前字符c比栈顶字符字典序小,并且栈顶字符在后续字符串中还有剩余(通过remainCounter.get(stack.peek()) > 0判断),则将栈顶字符从栈中弹出,并从seen集合中移除,继续循环比较新的栈顶字符,直到不满足条件。
  • 然后将当前字符c添加到栈stack中,并添加到seen集合中。
  1. 构建并返回结果

    通过遍历栈stack,将其中的字符依次添加到StringBuilder对象中,最后将StringBuilder对象转换为字符串并返回,得到去除重复字母且字典序最小的结果字符串。

  2. 有了基本的思路,接下来我们就来通过代码来实现一下。

🥦 实现代码
java 复制代码
class Solution {
    public String removeDuplicateLetters(String s) {
        int len = s.length();
        int[] lastIndex = new int[26];
        for(int i=0; i<len; i++){
            // 每个元素的最后出现的坐标
            lastIndex[s.charAt(i)-'a']=i;
        }
        // 栈中是否包含该元素
        boolean[] used = new boolean[26];
        Deque<Character> stack = new ArrayDeque<>();
        for(int i=0; i<len; i++){
            char ch = s.charAt(i);
            // 栈里面已经有该元素,直接跳过
            if(used[ch-'a']) continue;
            // 栈顶元素大于当前元素,且栈顶元素是重复元素,那肯定要出栈丢弃掉
            while(!stack.isEmpty()&& stack.peek()>ch && lastIndex[stack.peek()-'a']>i){
                used[stack.poll()-'a']=false;
            }
            // 栈里面没有当前元素,入栈
            stack.push(ch);
            used[ch-'a']=true;
        }
        StringBuilder ans = new StringBuilder();
        // 最后栈里面则为唯一元素,且维持原先相对顺序的字典顺序最小
        while(!stack.isEmpty()){
            ans.append(stack.poll());
        }
        return ans.reverse().toString();
    }
}
🥦 运行结果

💬 共勉

|----------------------------------|
| 最后,我想和大家分享一句一直激励我的座右铭,希望可以与大家共勉! |

相关推荐
CappuccinoRose6 分钟前
回溯法 - 软考备战(四十三)
算法·排列组合·路径·n皇后·子集·解数独·岛屿
AC赳赳老秦10 分钟前
OpenClaw进阶技巧:批量修改文件内容、替换关键词,解放双手
java·linux·人工智能·python·算法·测试用例·openclaw
Java小白笔记23 分钟前
OpenClaw 实战方法论
java·开发语言·人工智能·ai·全文检索·ai编程·ai写作
Robot_Nav44 分钟前
Shape-Aware MPPI(SA MPPI)算法:基于RC-ESDF的任意形状机器人实时轨迹优化
算法·机器人·sa-mppi
呱牛do it1 小时前
企业级门户网站设计与实现:基于SpringBoot + Vue3的全栈解决方案(Day 5)
java·vue
练习时长一年1 小时前
Spring配置类的演化
java·spring boot·spring
喜欢流萤吖~1 小时前
服务间的依赖管理:微服务的协作之道
java·微服务
invicinble1 小时前
Spring如何把bean注册到容器里
java·后端·spring
踩坑记录1 小时前
leetcode hot100 118. 杨辉三角 easy 动态规划
leetcode·动态规划
小O的算法实验室2 小时前
2026年ESWA,自适应基于排序的协同进化学习粒子群算法+边缘计算服务器部署,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进