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

💬 共勉

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

相关推荐
TPBoreas1 分钟前
Jenkins 改完端口号启动不起来了
java·开发语言
金斗潼关5 分钟前
SpringCloud GateWay网关
java·spring cloud·gateway
JK0x077 分钟前
代码随想录算法训练营 Day40 动态规划Ⅷ 股票问题
算法·动态规划
Feliz..7 分钟前
关于离散化算法的看法与感悟
算法
水蓝烟雨1 小时前
1128. 等价多米诺骨牌对的数量
算法·hot 100
codists1 小时前
《算法导论(第4版)》阅读笔记:p11-p13
算法
秋名RG1 小时前
深入解析建造者模式(Builder Pattern)——以Java实现复杂对象构建的艺术
java·开发语言·建造者模式
eternal__day1 小时前
Spring Boot 实现验证码生成与校验:从零开始构建安全登录系统
java·spring boot·后端·安全·java-ee·学习方法
陈大爷(有低保)2 小时前
swagger3融入springboot
java
Kidddddult3 小时前
力扣刷题Day 43:矩阵置零(73)
算法·leetcode·力扣