字符串 -- 字典序

定义:字典序(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 

*/