【刷题日记】316. 去除重复字母

简介: 本次刷题日记的第 42 篇,力扣题为:316. 去除重复字母 ,中等

【刷题日记】316. 去除重复字母

本次刷题日记的第 42 篇,力扣题为:316. 去除重复字母中等

一、题目描述:

image.png

乍一看这个题是什么感受,又是一个中等题,但是题目内容极少的一道题,我电脑一个屏就可以装下了,我们肯定可以解决


二、这道题考察了什么思想?你的思路是什么?

来看这题给我们展示了哪些重要的信息呢?

  • 题目给出的字符串中,只包含 26 个字母,且顺序是未知的
  • 题目要求我们按照去除字符串中重复的字符,且要保证字典序是最小的,还要求我们这些字母的相对位置需要正确

看到这里,是不是觉得这个题要求好多呀,不过没有关系,我们就像满足客户需求一样,分析好了可行性之后,再来满足需求

我们来看题目的要求,需要保证咱们的字母相对位置要是和题目给出的字符串相对位置要一样,那么我们其实就可以想到,应该是需要遍历题目给出的字符串的,这样做才是比较很简单的

那么对于去除重复的字符,这个也就更简单了,但是其实并不纯粹,因为我们去除的重复字母是需要有方法的,并不是随便就去掉了,因为,题目要求咱们保证字典序还要是最小的

那么这个需要如何思考呢?


第一要保证顺序,第二要去掉重复的字符,那么我们是否可以使用栈来保证顺序性呢?

如何保证字典序呢?字典序,我们是不是只需要保证 前一个字母大于后一个字母的时候,咱们就要把前一个字母干掉

咱们在遍历的过程中,保证好如上 3 点,那么一直遍历到字符串结尾,我们就可以得到答案了

大体思路我们可以这样来保证:

  • 使用一个 helper 数组来存放 26 个字母中,每个字符现在还剩余的个数,当有字符入栈的时候,这个 hepler 数组对应的字符数量就减去 1 个
  • 拿一个切片来模拟栈,遍历字符串的时候,校验当前字符是否小于栈顶元素,若是,那么就去掉栈顶元素,并将当前元素入栈
  • 拿一个hash表来记录,某个字母是否已经存在与栈中了

按照上述思路来进行编码的话,我们应该都能实现了吧

三、编码

根据上述逻辑和分析,我们就可以翻译成如下代码,

  • 这里需要注意,对于已经存在与栈里面的字符,我们就会再去校验他是否比栈顶的元素小了,因为按照之前的逻辑和流程,这种就需要跳过了
  • 另外对于校验到当前的元素比栈顶的小的时候,如果校验到栈顶的元素已经只有这一个了,那么我们也是需要跳过的
func removeDuplicateLetters(s string) string {
   // 定义一个数组,作为hash表,记录字符的剩余个数
    help := [26]int{}
    // 记录当前字符串中中每个字符的出现次数
    for _, ch := range s {
        help[ch-'a']++
    }
    // 用一个切片来模拟栈
    stack := []byte{}
    // 用于记录是否在栈中
    inStack := [26]bool{}
    for i := range s {
        ch := s[i]
        // 如果 ch 字符不在 栈中
        if !inStack[ch-'a'] {
            // 当前的栈切片是有值的,且当前的字符是小于栈顶字符的
            for len(stack) > 0 && ch < stack[len(stack)-1] {
                last := stack[len(stack)-1] - 'a'
                if help[last] == 0 {
                    break
                }
                // 去掉栈顶的元素
                stack = stack[:len(stack)-1]
                // 设置该字符不在栈中
                inStack[last] = false
            }
            stack = append(stack, ch)
            inStack[ch-'a'] = true
        }
        help[ch-'a']--
    }
    return string(stack)
}

按照如上实现的话,相信很容易就能看明白这个单调栈处理的方式吧,分析清楚了的话还是很简单的

四、总结:

就上述编码来看,这里的时间复杂度是多少呢,这个应该是非常明显的,因为我们只遍历了一次题目给出的字符串,所以时间复杂度是 O(n)

空间复杂度是 O(∣Σ∣) ,这个的含义在这里实际上是 26 ,因为咱们的字母个数只有 26 个,咱们引入的额外的空间是 26 个 int

原题地址:316. 去除重复字母

今天就到这里,学习所得,若有偏差,还请斧正

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image.png

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~


相关文章
|
BI
7-6 sdut-C语言实验-最长上升子序列
7-6 sdut-C语言实验-最长上升子序列
256 1
|
Linux 开发工具
18.4 【Linux】systemd-journald.service 简介
18.4 【Linux】systemd-journald.service 简介
511 0
|
Kubernetes Ubuntu 网络协议
超好用的k8s中pod诊断工具:kubectl-debug
超好用的k8s中pod诊断工具:kubectl-debug
超好用的k8s中pod诊断工具:kubectl-debug
|
10月前
|
前端开发 Java 关系型数据库
基于ssm的社区物业管理系统,附源码+数据库+论文+任务书
社区物业管理系统采用B/S架构,基于Java语言开发,使用MySQL数据库。系统涵盖个人中心、用户管理、楼盘管理、收费管理、停车登记、报修与投诉管理等功能模块,方便管理员及用户操作。前端采用Vue、HTML、JavaScript等技术,后端使用SSM框架。系统支持远程安装调试,确保顺利运行。提供演示视频和详细文档截图,帮助用户快速上手。
457 17
|
算法 Java 数据库
理解CAS算法原理
CAS(Compare and Swap,比较并交换)是一种无锁算法,用于实现多线程环境下的原子操作。它通过比较内存中的值与预期值是否相同来决定是否进行更新。JDK 5引入了基于CAS的乐观锁机制,替代了传统的synchronized独占锁,提升了并发性能。然而,CAS存在ABA问题、循环时间长开销大和只能保证单个共享变量原子性等缺点。为解决这些问题,可以使用版本号机制、合并多个变量或引入pause指令优化CPU执行效率。CAS广泛应用于JDK的原子类中,如AtomicInteger.incrementAndGet(),利用底层Unsafe库实现高效的无锁自增操作。
552 0
理解CAS算法原理
|
10月前
|
编解码 监控 开发工具
H.264语法结构分析之frame_cropping_flag
本文深入探讨了H.264标准中的`frame_cropping_flag`,一个常被提及却易被误解的概念。该标志用于指示解码后图像是否需裁剪,通过四个裁剪偏移量参数调整分辨率。文章分析了其在视频转码、流处理及编辑中的应用,并讨论对视频质量的影响,如内容完整性、分辨率调整和传输效率。合理设置此参数可优化视频适配与播放体验,但需注意兼容性问题。最后强调,理解音视频协议框架对开发高质量播放器至关重要。
274 9
|
人工智能 运维 监控
云卓越架构:企业稳定性架构体系和AI业务场景探秘
本次分享由阿里云智能集团公共云技术服务部上海零售技术服务高级经理路志华主讲,主题为“云卓越架构:企业稳定性架构体系和AI业务场景探秘”。内容涵盖四个部分:1) 稳定性架构设计,强调高可用、可扩展性、安全性和可维护性;2) 稳定性保障体系和应急体系的建立,确保快速响应和恢复;3) 重大活动时的稳定重宝策略,如大促或新业务上线;4) AI在企业中的应用场景,包括智能编码、知识库问答、创意广告生成等。通过这些内容,帮助企业在云计算环境中构建更加稳定和高效的架构,并探索AI技术带来的创新机会。
|
机器学习/深度学习 编解码 自然语言处理
论文阅读笔记 | Transformer系列——Swin Transformer
论文阅读笔记 | Transformer系列——Swin Transformer
2224 0
论文阅读笔记 | Transformer系列——Swin Transformer
|
Linux Docker 容器
docker 国内镜像源
【8月更文挑战第26天】
5533 1