字符串 -- 字典序
定义:字典序(dictionary order),又称 字母序(alphabetical order),原意是表示英文单词在字典中的先后顺序,在计算机领域中扩展成两个任意字符串的大小关系。
英文中的 字母表(Alphabet) 按照如下的顺序排列:
ABCDEFG HIJKLMN OPQRST UVWXYZ
abcdefg hijklmn opqrst uvwxyz
比如:b > a,apple > a,hat > cap, astronomy > as pass > Pass ……
即:先比较第一个字母,若第一个字母相同,则比较第二个字母的字典序,依次类推,则可比较出该字符串的字典序大小.
再有一个知识点:区分子序列和子串
如有一字符串:abbsd
子序列是 abs,ad,其中的字符在字符串中不一定是连在一起的.
子串是ab,abbs,sd,其中的字符在字符串中一定是连在一起的.
例题1 -- 找最大字典序的子序列:
给定字符串s,s只包含小写字母,请求出字典序最大的子序列。
子序列:https://en.wikipedia.org/wiki/Subsequence
字典序:https://en.wikipedia.org/wiki/Lexicographical_order
输入描述:
一行一个字符串s (1 <= |s| <= 100,000)。
输出描述:
字典序最大的子序列。
输入
ababba
输出
bbba
输入
abbcbccacbbcbaaba
输出
cccccbba
题解:最后一个字符肯定是最大子序列中的一个字符,然后假定最大的字符为'a',从字符串最后一个字符开始变量,若该字符大于或等于最大字符,则让该字符入栈,并且将该字符替换成最大的字符.
AC代码:
#include<stdio.h>
#include<iostream>
#include<stack>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 7;
const int maxm = 2e5 + 7;
const long long inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;
stack<char> ss;
char str[maxn], ans[maxn];
int main()
{
scanf("%s",str);
int len = strlen(str);
char max = 'a';
int cnt = 0;
for(int i = len; i >= 0; i--)
{
if(str[i] >= max)
{
max = str[i];
ss.push(max);
}
}
while(ss.size())
{
printf("%c",ss.top());
ss.pop();
}
return 0;
} // 栈的写法.
/*
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 7;
const int maxm = 2e5 + 7;
const long long inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;
char str[maxn], ans[maxn];
int main()
{
scanf("%s",str);
int len = strlen(str);
char max = 'a';
int cnt = 0;
for(int i = len; i >= 0; i--)
{
if(str[i] >= max)
{
max = str[i];
ans[cnt++] = str[i];
}
}
for(int i = cnt - 1; i >= 0; i--)
printf("%c",ans[i]);
return 0;
}
*/
例题2 -- 找最大字典序的子串:
字符串的子串是指字符串中连续的一段。
给定字符串s,请你找出字典序最大的子串。
输入描述:
一行,包含一个字符串,字符串中只有小写英文字母,字符串的长度不超过1000。
输出描述:
输出一个字符串,表示字符串s字典序最大的子串。
输入
ac
输出
c
说明
子串有三个,a,c,ac,字典序最大的是c
题解:先找到最大字典序的字符,假如有相同的,就用两个"哨兵"开始分别以这两个相同字符为起点开始往后遍历,直到遍历到二者不相同为止,注意的是当遍历到不相同的时候必须立即break,不然可能出现你真的会WAWA大哭,假设字符串为:cbbcac,(悄咪咪说一句,这就是把我代码hack掉的数据),我们不难发现,str[0] == str[3] ,接着我们会遍历,str[1] > str[4],所以起点位置不用改变,但是我们此时不break会继续遍历,str[2] < str[5],结果起点位置变为第二个c的位置也就是 bg = 3, 最后直接输出后缀cac,但是正确答案是cbbcac。当我们确定了起点位置的时候就直接输出后缀即可.
AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 7;
const int maxm = 2e5 + 7;
const int num = 1005;
const long long inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;
char str[num];
int main()
{
while(~scanf("%s",str))
{
int len = strlen(str);
int bg = 0;
for(int i = 1; i < len; i++)
{
if(str[i] > str[bg]) //找出最大字母,若无相同的直接输出后缀
bg = i;
else if(str[i] == str[bg]) //若有相同的比较二者的下一个字符字典序
{
for(int j = bg, k = i; j < len && k < len; j ++, k++)
{
if(str[k] != str[j])
{
if(str[k] > str[j])
bg = i;
break;
}
}
}
}
for(int i = bg; i < len; i++)
printf("%c",str[i]);
printf("\n");
}
return 0;
}
/*
cbbcac
babb
*/