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

Posted 英雄哪里出来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 2030. 含特定字母的最小子序列相关的知识,希望对你有一定的参考价值。

文章目录

一、题目

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讲》🌌

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

竞赛选手金典图文教程
💜《夜深人静写算法》💜

以上是关于LeetCode 2030. 含特定字母的最小子序列的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode——不同字符的最小子序列/去除重复字母

1081. 不同字符的最小子序列

LeetCode 1403.非递增顺序的最小子序列

算法题-第K个小子串

LeetCode Algorithm 1403. 非递增顺序的最小子序列

LeetCode Algorithm 1403. 非递增顺序的最小子序列