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

💬 共勉

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

相关推荐
爱喝水的鱼丶13 分钟前
SAP-ABAP:条件判断与循环控制语句(7篇)第七篇:性能优化:条件与循环代码的常见性能瓶颈与优化方案
学习·算法·性能优化·sap·abap
吃好睡好便好5 小时前
提取矩阵某一行或某一列元素
开发语言·人工智能·线性代数·算法·matlab·矩阵
better_liang7 小时前
每日Java面试场景题知识点之-消息队列MQ核心场景与实战
java·面试·kafka·消息队列·rabbitmq·rocketmq·mq
小江的记录本8 小时前
【JVM虚拟机】垃圾回收GC:四种引用类型:强引用、软引用、弱引用、虚引用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
圣保罗的大教堂8 小时前
leetcode 2540. 最小公共值 简单
leetcode
小马爱打代码8 小时前
Spring源码 第四篇:Spring 5 源码深度拆解:AOP 全流程核心原理
java·后端·spring
better_liang8 小时前
每日Java面试场景题知识点之-SpringBoot启动流程
java·面试·springboot·源码解析·启动流程
RyFit8 小时前
Java + AI 实战:Spring AI 从入门到企业级落地
java·人工智能·spring
云泽8089 小时前
笔试算法 -位运算篇(二):从唯一字符到消失数字
c++·算法·位运算
ʚ希希ɞ ྀ9 小时前
不同路径|| -- dp
算法