字符串 -- 字典序
定義:字典序(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
*/