LeetCode 2030. 含特定字母的最小子序列

本文介绍了一种利用单调栈解决LeetCode 2030题目的方法,详细阐述了解题思路、时间复杂度和代码实现。解题过程中,首先分析了题目条件,然后通过建立单调栈来找到字典序最小的子序列,同时确保特定字母出现指定次数。最后给出了详细的代码解释和解题过程中的关键知识点,帮助读者理解如何在满足特定约束条件下找到最小子序列。
摘要由CSDN通过智能技术生成

一、题目

1、题目描述

  给你一个字符串 s s s ,一个整数 k k k ,一个字母 letter以及另一个整数 repetition
  返回 s s s 中长度为 k k k 且 字典序最小 的子序列,该子序列同时应满足字母 letter出现 至少 repetition次。生成的测试用例满足 letter s s s 中出现 至少 repetition次。
  样例输入: s = "leetcode", k = 4, letter = "e", repetition = 2
  样例输出: "ecde"

2、基础框架

  • C++ 版本给出的基础框架代码如下:
class Solution {
public:
    string smallestSubsequence(string s, int k, char letter, int repetition) {
        
    }
};

3、原题链接

LeetCode 2030. 含特定字母的最小子序列

二、解题报告

1、思路分析

   ( 1 ) (1) (1) 首先梳理条件:
     ( 1.1 ) (1.1) (1.1) 长度为 k k k 的子序列;
     ( 1.2 ) (1.2) (1.2) 字典序最小;
     ( 1.3 ) (1.3) (1.3) 正好有 repetition个字符letter
   ( 2 ) (2) (2) 如果没有第三个条件,我们怎么做?
   ( 3 ) (3) (3) 可以考虑用一个栈,栈里的元素,从栈底到栈顶单调不降。考虑栈顶元素 x x x,当前枚举到的元素 y y y,并且栈里的元素 + 还没有枚举的元素的个数,大于等于 k k k,有三种情况:
     ( 3.1 ) (3.1) (3.1) x > y x \gt y x>y,将 x x x 出栈。反复判断,直到栈底到栈顶单调不降。
     ( 3.2 ) (3.2) (3.2) y y y 入栈;
   ( 4 ) (4) (4) 模拟一下leetcode这个单词:
     ( 4.1 ) (4.1) (4.1) l入栈;
     ( 4.2 ) (4.2) (4.2) l > e,则l出栈,e入栈;
     ( 4.3 ) (4.3) (4.3) e <= ee入栈;
     ( 4.4 ) (4.4) (4.4) e < tt入栈;
     ( 4.5 ) (4.5) (4.5) t > c,则t出栈,则e出栈,则e出栈,则l出栈,c入栈;
     ( 4.6 ) (4.6) (4.6) 这时候栈里面一个c,外面只剩下ode,总共四个字符,所以就是code为字典序最小的情况;当然,这是没有考虑repetition的情况时的解。最后,将栈强制出栈得到一个 k k k 个长度的栈,逆序就是要求的满足条件 ( 1.1 ) (1.1) (1.1) ( 1.2 ) (1.2) (1.2) 的字符串。

   ( 7 ) (7) (7) 那么,如何满足正好有 repetition个字符letter字符呢?
   ( 8 ) (8) (8) 首先,可以用一个后缀和来记录后面的字符串,还有多少个letter字符。以及cnt代表当前栈中有多少个字符,进行出栈之前需要增加一个条件:如果栈中letter字符 + 后缀还剩余字符等于repetition,并且当前栈顶元素是letter字符,则不能出栈。
   ( 9 ) (9) (9) 遍历完毕以后,栈中的字符数可能大于 k k k 个,于是需要去掉末尾的字符,并且记录多删除的letter的数目,并且在最后给它补偿回来。

2、时间复杂度

   时间复杂度 O ( n ) O(n) O(n)

3、代码详解

class Solution {
public:
    string smallestSubsequence(string s, int k, char letter, int repetition) {
        int sum[100000], hash[100000];
    
        stack<char> stk;    
        string ret;
        int i;
        int n = s.size();
        int cnt = 0;
        sum[n] = 0;
        for(i = n-1; i >= 0; --i) {
            sum[i] = (s[i] == letter ? 1 : 0) + sum[i+1];
        }

        for(i = 0; i < n; ++i) {
            while(stk.size() + (n - i) > k && stk.size() && stk.top() > s[i]) {
                if(cnt + sum[i] == repetition && stk.top() == letter) {
                    break;
                }
                if(stk.top() == letter) --cnt;
                stk.pop();
            }
            stk.push(s[i]);
            if(s[i] == letter) ++cnt;
        }

        // 这一趟下来,cnt == repetition,但是长度有可能大于 k

        while(stk.size() > k) {
            cnt -= (stk.top() == letter ? 1 : 0);
            stk.pop();
        }
        while(stk.size()) {
            ret += stk.top();
            stk.pop();
        }
        reverse(ret.begin(), ret.end());

        int x = k - 1;
        while(cnt < repetition) {
            cnt += (ret[x] != letter);
            ret[x] = letter;
            --x;
        }

        return ret;
    }
}; 

三、本题小知识

  单调栈的问题,可以先考虑两个元素的大小关系,逐渐就能清晰的明白栈是应该用递增栈,还是递减栈。


四、加群须知

  相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」
  那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:

🌌《算法入门指引》🌌

  如果链接被屏蔽,或者有权限问题,可以私聊作者解决。

  大致题集一览:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述



在这里插入图片描述


  为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
  不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」
  🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥


🔥让天下没有难学的算法🔥

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

让你养成九天持续刷题的习惯
🔥《九日集训》🔥

入门级C语言真题汇总
🧡《C语言入门100例》🧡

组团学习,抱团生长
🌌《算法零基础100讲》🌌

几张动图学会一种数据结构
🌳《画解数据结构》🌳

竞赛选手金典图文教程
💜《夜深人静写算法》💜
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值