算法:字典序问题
前言
用来记录和分享自己的算法学习过程和解题思路 0.0
一、题目
问题描述:
在数据加密和数据压缩中常需要对特殊的字符串进行编码.给定的字母表A由26个小写英文字母组成,即A={a,b…z}.该字母表产生的长序字符串是指定字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次.例如,a,b,ab,bc,xyz,等字符串是升序字符串.现在对字母表A产生的所有长度不超过6的升序字符串按照字典排列编码如下:
1 2 3 …26 27 28 …
a b c …z ab ac …
对于任意长度不超过6的升序字符串,迅速计算出它在上述字典中的编码。
二、解题思路
主要思路是将一个字符串分成两部分计算,一部分是头,一部分是躯干。
头部分的计算利用递归思路解决;躯干部分则利用差值求解
具体有空再补全QAQ
举例说明一下:
若求axy的编码,我的思路是将其分为两部分.其一:abc的编码(以a为首的三位长的第一个编码),
其二:xy与bc的编码差.两部分加起来后则得当前axy的编码.
后者可以递归利用求取编码的函数得到;而abc的编码,则利用xy(两位长度下最后一个字符串编码)
+1求取.
同理,若求 bxy编码,则求取以b为首的bcd编码+xy-cd,而bcd的编码则为axy的编码+1(同理以用递归求解)
三、代码
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
string Headend(int length);
string Headnext(string str,int length);
int Differ(string a,string b);
int Dic(string a);
//求某长度下某首字母长度
int Flength(string a,int length)
{
//例:当求abc中,以a为首的长度时,只需求yz序列+1即可
if(a[0]=='a')
return Dic(Headend(length))+1;
else
{
//若是找d开头且三位长的权重,等于c开头长度+yz-de
char ch=a[0]-1;
string s;
s.push_back(ch);
int aa=Flength(s,length),b=Differ(Headnext(s,length),Headend(length));
return aa+b+1;
}
}
//求两字符串序列差
int Differ(string a,string b)
{
return Dic(b)-Dic(a);
}
//求某字母后面紧跟着的部分 如三个长度下a后面就是bc
string Headnext(string str,int length)
{
length=length-1;
string s;
for(int i=0;i<length;i++)
{
char ch=str[0]+i+1;
s.push_back(ch);
}
return s;
}
//求某长度下最后那部分,如三个长度下最后部分yz
string Headend(int length)
{
string s;
for(int i=length-1;i>0;i--)
{
char ch='z'-i+1;
s.push_back(ch);
}
return s;
}
//求某字符串顺序
int Dic(string a)
{
if(a.length()==1)
return a[0]-'a'+1;
else if(a.length()==2)
{
return 26*(a[0]-'a'+1)+a[1]-'a'+1-(a[0]-'a'+2)*(a[0]-'a'+1)/2;
}
else
{
//头和躯干分离计算,即首字母序列+后面几个序列的序列差
string head(a.substr(0,1)),body(a.substr(1,a.length()-1));
return Flength(head,a.length())+Differ(Headnext(a,a.length()),body);
}
}
int main()
{
string str;
cin>>str;
int num=Dic(str);
cout<<num<<endl;
}