zoukankan      html  css  js  c++  java
  • UPC-6597 Don't Be a Subsequence(字符串最短不存在子串)

    题目描述
    A subsequence of a string S is a string that can be obtained by deleting zero or more characters from S without changing the order of the remaining characters. For example, arc, artistic and (an empty string) are all subsequences of artistic; abc and ci are not.
    You are given a string A consisting of lowercase English letters. Find the shortest string among the strings consisting of lowercase English letters that are not subsequences of A. If there are more than one such string, find the lexicographically smallest one among them.

    Constraints
    1≤|A|≤2×105
    A consists of lowercase English letters.

    输入
    Input is given from Standard Input in the following format:
    A

    输出
    Print the lexicographically smallest string among the shortest strings consisting of lowercase English letters that are not subsequences of A.

    样例输入
    atcoderregularcontest

    样例输出
    b

    提示
    The string atcoderregularcontest contains a as a subsequence, but not b.

    题意:给出一个字符串,输出该字符串中字典序最小的不存在子串

    不存在子串意思是该串进行删除某些字符的操作后,以原来的顺序排列剩余的字符无法构造出的字典序最小的字符串,如一个串是从a~z的,那么该串中最小字典序的不存在子串将不是a~z中的任意一个字母,说明其不存在子串至少是两个字母的,如aa。
    又如一个串中出现了两次a~z的排列,那么通过删除该串中的一些字符,将可以构造出任意两个字母组成的子串。

    通过从后往前的遍历顺序,处理好对于每个位置,其下一个字符在哪个位置,下一个字符指的是26个字母中所有字母的位置,即str[i]->letter[1~26],记录位置是为了方便查询该位置之后不存在哪些字母,以及如果所有字母都存在,那么应该输出哪些字母使得总输出长度最短【字典序最小】。记录一个离当前位置到不存在某个后续字母的最短长度len,即str[i]->len[1~26],意思是若当前位置输出了某个字母,那还应输出多少字母才能结束输出。

    在倒叙遍历过程中更新这两个数组。用Pos数组记录一个离当前位置最近的26个字母的位置,那么pos[0]就表示离当前遍历位置最近的a字母在的位置。利用这个数组去更新str[i]->nxt[j],而pos的更新就很方便了,直接外层遍历字符串时每遍历一个位置的字符就更新该字符的相应位置。对于minlen,每次取当前位置下一个字母的最小值赋值,这样就形成了利用str[i]->len[j]更新最小minlen,又用minlen更新各个位置的len【i】的形式。

    这样处理好两个数组后,从字符串开始查询不存在的字母,若都存在,查询输出哪个字母使得总输出量最短,即符合最小字典序,
    【*感谢zls提供思路https://blog.csdn.net/qq_17456531

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+10;
    const int inf=0x3f3f3f3f;
    char a[maxn];
    struct str
    {
        int len[26],nxt[26];
    } word[maxn];
    int pos[26];///离当前位置最近的26个字母的位置
    int minlen[maxn];
    int main()
    {
        scanf("%s",a+1);
        memset(pos,0,sizeof pos);
        int len=strlen(a+1);
        for(int i=len; i>=0; i--)///倒叙遍历字符串,以查询离每个位置最近的下一个字母
        {
            minlen[i]=inf;///当前位置往后可查询的不存在子串的最小长度
            for(int j=0; j<26; j++)///对于第i位,其下一个26个字母中每个字母的位置是谁
            {
                word[i].nxt[j]=0;///如下一个字母a的位置
                if(pos[j])///若该位置之后存在该字母
                {
                    word[i].nxt[j]=pos[j];///给出下一个该字母的位置
                    word[i].len[j]=minlen[pos[j]]+1;///给当前位置最短不存在子串的长度赋予上一个位置+1的长度,因为该位置存在字母j,如果查找该位最小字典序那么长度就要相应增加
                    if(i==0)word[i].len[j]--;///如果是第一个位置,长度不用加一
                }
                else word[i].len[j]= i==0?0:1;///如果不存在某个字母,那说明到此结束,不存在子串长度截止
                minlen[i]=min(minlen[i],word[i].len[j]);
            }
            if(i!=0)pos[a[i]-'a']=i;///如果不是第一个字符,更新当前出现字母的最新位置
        }
        for(int k=0,mini,minn;; k=word[k].nxt[mini],printf("%c",mini+'a'))///输出部分,每次利用之前处理的当前位置的下一个字母和最短长度输出相应字符
        {///指针后移
            mini=0,minn=inf;
            for(int i=0; i<26; i++)///每次查找下一个输出的字符,保证整体输出长度最小
            {
                if(!word[k].nxt[i])///若之后不存在某个字母了,那就输出结束了
                {
                    printf("%c
    ",i+'a');
                    return 0;
                }
                if(word[k].len[i]<minn)minn=word[k].len[i],mini=i;///记录最小输出长度的字母
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    PostgreSQL安装的后续工作
    进程在Linux上实际需要多少内存
    PostgreSQL的大对象以及空间使用 (3)
    PostgreSQL的大对象以及空间使用 (2)
    PostgreSQL的大对象以及空间使用 (1)
    PostgreSQL的WAL(4)--WAL创建和调优
    Cannot set Column 'EffectiveDate' to be null. Please use DBNull instead.
    除去datatable的空行
    sql like in 语句获取以逗号分割的字段内的数据
    el-cascader 设置选中任意一级
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135720.html
Copyright © 2011-2022 走看看