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

💬 共勉

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

相关推荐
葡萄成熟时 !4 小时前
JAVA 常用API学习笔记
java·笔记·学习
鹿角片ljp5 小时前
LeetCode 46. 全排列|吃透回溯
算法·leetcode·职场和发展
鼎艺创新科技5 小时前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
Rain的Java大神之路5 小时前
介绍一下分布式事务
java·分布式·后端·spring·spring cloud·架构·springcloud
吴声子夜歌6 小时前
Java面试题——基础(一)
java·开发语言
南城以南溫暖如初1477 小时前
外卖CPS实战指南:从技术选型到运营落地全流程解析
java·spring boot·mysql·架构·vue
傻啦嘿哟7 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
.道阻且长.8 小时前
11.LeetCode算法习题讲解--滑动窗口--将x减到0的最小操作数
算法·leetcode·职场和发展
码匠许师傅8 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
wenyq78 小时前
LeetCode 2460. Apply Operations to an Array
算法·leetcode