[补题]找到原序列长度k的子序列中字典序最小的那个(单调栈)

题意

题目如题,输入序列只包含小写字母,数据范围0<k<=len<=500000。
例:
输入:helloworld
输出:ellld

题解

  • 使用单调栈。当已删掉n-k个字符,输出栈中元素和剩余序列。否则当完成遍历一遍序列,输出栈底k个元素。时间复杂度O(n)。
  • 我的思考
    • 之前的思路是按序遍历26个字母,并遍历原序列的子区间(beg,end)其中beg是上一次找到的字符的下一个,end是不至于凑不够k的结尾处。写好并超时了。时间复杂度大概是O(k ·logn ·26)。
    • 大概想的优化是排序/滑动窗口一样的东西搞成O(n),原因是单调栈并不知道什么时候用用的太少。
    • 不知道怎么处理的点是找更新区间的最小字典序字符,以及字典序小但出现在结尾处的字符怎么处理(类似例子中的d)。单调栈+删掉n-k提前截止很好的处理了我两个不会处理的点。仔细体会吧。
    • 起码下次要有优化到O(n)的方法考虑一波单调栈的意识。

相关知识

单调栈

  • 定义:栈中的元素是按照某种方式排列,但是必须是单调的。如果某元素破坏了栈的单调性,就弹出栈的元素,直到该元素满足栈的单调性为止。
  • 用途:使用单调栈可以找到元素向左遍历第一个比他小/大的元素,也可以找到元素向左遍历第一个比他大/小的元素,且时间复杂度O(n)

单调队列

  • 定义:队列单调递增或递减。不断地向缓存数组里读入元素,也不时地去掉最老的元素,不定期的询问当前缓存数组里的最小的元素。
  • 用途:用单调队列来解决问题,一般都是需要得到当前的某个范围内的最小值或最大值

代码

import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;

public class subStr {
    public static void main(String args[]) {
        Scanner in=new Scanner(System.in);
        String str=in.next();
        int k=in.nextInt();     

        Stack<Character> stack=new Stack<>();
        int cntToDel=str.length()-k;
        for(int i=0;i<str.length();++i) {
            while(!stack.isEmpty()&&cntToDel!=0&&stack.peek()>str.charAt(i)) {
                    stack.pop();
                    --cntToDel;
            }

            //如果已经删了n-k个元素
            if(cntToDel==0) {
                LinkedList<Character> list=new LinkedList<>();
                while(!stack.isEmpty()) {
                    list.add(stack.pop());
                }
                Collections.reverse(list);

                for(Character c:list) {
                    System.out.print(c);
                }
                String tailStr=str.substring(i,str.length());
                System.out.print(tailStr);
                return;
            }

            stack.add(str.charAt(i));
        }

        //字符串完成了一遍遍历,输出单调栈底下的k个。
        LinkedList<Character> list=new LinkedList<>();
        while(!stack.isEmpty()) {
            list.add(stack.pop());
        }
        Collections.reverse(list);

        String subStr=str.substring(0,k);
        System.out.print(subStr);
    }
}

参考链接

https://blog.csdn.net/ljd201724114126/article/details/80663855

原文地址:https://www.cnblogs.com/coding-gaga/p/11032539.html

时间: 2024-11-20 22:08:10

[补题]找到原序列长度k的子序列中字典序最小的那个(单调栈)的相关文章

转:最小区间:k个有序的数组,找到最小区间使k个数组中每个数组至少有一个数在区间中

转:http://www.itmian4.com/thread-6504-1-1.html 最小区间原题 k个有序的数组,找到最小的区间范围使得这k个数组中,每个数组至少有一个数字在这个区间范围内.比如: 数组1:[4, 10, 15, 24, 26] 数组2:[0, 9, 12, 20] 数组3:[5, 18, 22, 30] 最小的区间是[20, 24],这个区间包含了数组1中的24,数组2中的20,数组3中的22 思考时间~~~ 分析 该题看起来还算比较简单,大家通常都会想到:为每一个数组

POJ 3415 Common Substrings(长度不小于k 的公共子串的个数--后缀数组+单调栈优化)

题意:给定两个字符串A 和B,求长度不小于k 的公共子串的个数(可以相同). 样例1: A="xx",B="xx",k=1,长度不小于k 的公共子串的个数是5. 样例2: A ="aababaa",B ="abaabaa",k=2,长度不小于k 的公共子串的个数是22. 思路: 如果i后缀与j后缀的LCP长度为L, 在L不小于K的情况下, 它对答案的贡献为L - K + 1. 于是我们可以将两个串连起来, 中间加个奇葩的分隔符

[ACM] POJ 2796 Feel Good (求序列中子序列的和与子序列中的最小数最大乘积)

Feel Good Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9186   Accepted: 2509 Case Time Limit: 1000MS   Special Judge Description Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated

【poj3415-长度不小于k的公共子串个数】后缀数组+单调栈

这题曾经用sam打过,现在学sa再来做一遍. 基本思路:计算A所有的后缀和B所有后缀之间的最长公共前缀. 分组之后,假设现在是做B的后缀.前面的串能和当前的B后缀产生的公共前缀必定是从前往后单调递增的,每次与h[i]取min时必定将栈尾一些长的全部取出来,搞成一个短的. 所以就开一个栈,栈里存的是长度,同时存一下它的出现此处cnt. 注意各种细节啊.. 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring>

loj rounds 补题

LibreOJ β Round ZQC 的树列 考虑原序列中的所有子序列中,美观值最大的一定是原序列. 那么这些子序列美观度与原序列相同的充要条件是包含每个最值点. 由于我们要构造一个特征值为\(k\)的序列.其实只用\(0, 1, 2\)三种元素就能构造.构造的序列一定是一段0(,一段1),一段2(,一段1),一段0(,一段1)... 考虑一段长度为\(l\)的连续1的贡献为\(2 ^ l\),一段长度为\(l\)的连续0或2的贡献为\(2 ^ l - 1\).相当于把\(k\)分解成这种数的

2020-3-14 acm训练联盟周赛Preliminaries for Benelux Algorithm Programming Contest 2019 解题报告+补题报告

2020-3-15比赛解题报告+2020-3-8—2020-3-15的补题报告 2020-3-15比赛题解 训练联盟周赛Preliminaries for Benelux Algorithm Programming Contest 2019  A建筑(模拟) 耗时:3ms 244KB 建筑 你哥哥在最近的建筑问题突破大会上获得了一个奖项 并获得了千载难逢的重新设计城市中心的机会 他最喜欢的城市奈梅根.由于城市布局中最引人注目的部分是天际线, 你的兄弟已经开始为他想要北方和东方的天际线画一些想法

4.30-5.1cf补题

//yy:拒绝转载!!! 悄悄告诉你,做题累了,去打两把斗地主就能恢复了喔~~~ //yy:可是我不会斗地主吖("'▽'") ~~~那就听两遍小苹果嘛~~~ 五一假期除了花时间建模,就抽空把最近没做的CF题补了点..毕竟明天开始又要继续上好多课呐...Yes, I can!(? •_•)?……(I can Huá shuǐ~~) codeforces 803 A. Maximal Binary Matrix   [简单构造] 题意:n行和n列填充零矩阵. 您要将k个1放在其中,使得得到

2018 HDU多校第三场赛后补题

2018 HDU多校第三场赛后补题 从易到难来写吧,其中题意有些直接摘了Claris的,数据范围是就不标了. 如果需要可以去hdu题库里找.题号是6319 - 6331. L. Visual Cube 题意: 在画布上画一个三维立方体. 题解: 模拟即可. 代码: #include <bits/stdc++.h> using namespace std; int a, b, c, R, C; char g[505][505]; int main () { int T; cin >>

code M资格赛 补题

A: 音乐研究 时间限制:1秒 空间限制:32768K 美团外卖的品牌代言人袋鼠先生最近正在进行音乐研究.他有两段音频,每段音频是一个表示音高的序列.现在袋鼠先生想要在第二段音频中找出与第一段音频最相近的部分. 具体地说,就是在第二段音频中找到一个长度和第一段音频相等且是连续的子序列,使得它们的 difference 最小.两段等长音频的 difference 定义为:difference = SUM(a[i] - b[i])2 (1 ≤ i ≤ n),其中SUM()表示求和 其中 n 表示序列