【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();
    }
}
🥦 运行结果

💬 共勉

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

相关推荐
异常君33 分钟前
深入理解 Java Stream.reduce()方法:原理解析与实战应用
java
啊阿狸不会拉杆1 小时前
《软件工程》实战— 在线教育平台开发
java·vue.js·软件工程·团队开发
移动开发者1号1 小时前
Fragment事务commit与commitNow区别
android·java
꧁༺摩༒西༻꧂1 小时前
Python生成日历导出Excel
java·前端·python
在未来等你2 小时前
互联网大厂Java求职面试:AI大模型融合下的企业知识库架构设计与性能优化
java·向量数据库·ai大模型·spring ai·语义缓存·rag系统·多模态处理
蒟蒻小袁2 小时前
力扣面试150题--二叉树的层平均值
算法·leetcode·面试
寻星探路2 小时前
JAVA与C语言之间的差异(一)
java·开发语言
geneculture2 小时前
技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型
大数据·人工智能·算法·数学建模·智能硬件·工程技术·融智学的重要应用
tqs_123452 小时前
IntelliJ IDEA 中进行背景设置
java·ide·intellij-idea
1001101_QIA2 小时前
【QT】理解QT机制之“元对象系统”
开发语言·c++·qt·算法