在数据加密和数据压缩中常需要对特殊的字符串进行编码.给定的字母表A由26个小写英文字母组成,即A={a,b...z}.
该字母表产生的长序字符串是指定字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次.
例如,a,b,ab,bc,xyz,等字符串是升序字符串.现在对字母表A产生的所有长度不超过6的升序字符串按照字典排列编码如下:
1 2 …… 26 27 28 ……
a b …… z ab ac ……
对于任意长度不超过6的升序字符串,迅速计算出它在上述字典中的编码。
上面公式可以这么理解:因为升序字符串,所以右边位上的字符要比左边的大
f(i,k)表示为第一个为第i个的字符,长度不超过k的升序字符串个数 = 所有第一个字符为大于第i个的字符,长度不超过k-1的升序字符串个数的总和。
//计算以i开始长度为k的升序字符串数的个数
public static int f(int i, int k){
int sum = 0;
if (k == 1) sum += 1;
else
for (int j = i + 1; j <= 26; j++) sum += f(j, k - 1);
return sum;
}
g(k)表示为长度不超过k的升序字符串个数 = 所有第一个为第i个的字符长度不超过k的升序字符串个数的总和(1<=i<=26)
//长度不超过K的升序字符串个数
public static int g(int k){
int sum = 0;
for (int i = 1; i <= 26; i++) sum += f(i, k);
return sum;
}
题目简化: 对每个长度不超过6的升序字符串算出对应的值
public static int DictionarySequence(string str){
int sum = 0;
//获取前1~length-1长度的子字符串数
for (int i = 1; i < str.Length; i++) sum += g(i);
int temp = str.First() - 'a' + 1;
//获取 小于第一个字符 长度为length的字符串数
for(int i=1;i<temp;i++) sum += f(i, str.Length);
//以temp为第一个字符开始的字符串个数
for (int i = 1; i < str.Length; i++)
{
int next = str.ElementAt(i)-'a'+1; //为temp的后一位字符
int length = str.Length - i;
//获取比next小,大于temp的(因为升序) 长度为length的所有字符串个数
for (int j = temp + 1; j < next; j++) sum += f(j, length);
temp = next;
}
return sum+1;//加1是因为该字符串自己
}