1-2 字典序问题

在数据加密和数据压缩中常需要对特殊的字符串进行编码.给定的字母表A由26个小写英文字母组成,即A={a,b...z}.该
字母表产生的长序字符串是指定字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最
多出现1次.例如,a,b,ab,bc,xyz,等字符串是升序字符串.

思想:排列组合问题

考察一般情况下长度不超过k的升序字符串

设以第i个字符打头的长度k的升序字符串个数位f(i,k),长度k的升序字符串总个数为g(k),则

g(k)=累加f(i,k),i从1到26

f(i,1)=1                                                                                  g(1)=累加f(i,1),i从1到26

f(i,2)=累加f(j,1)=26-i,j从i+1到26                                           g(2)=累加f(i,2)=累加(26-i),i从1到26

一般情况,有:

f(i,k)=累加f(j,k-1),j从i+1到26                                          

g(k)=累加f(i,k)=累加i(累加j,f(j,k-1)),i从1到26,j从i+1到26

举例:对于字符串cfkn,首先有g(3),g(2),g(1)                                         长度小于4的所有串的个数

                                       其次有f(2,4),f(1,4)                                             首位小于第一个字母的4长度串的个数

                                       再次f(4,3),f(5,3)                                               以d,e开头的长度为3的串的个数

                                       再其次f(7,2),f(8,2),f(9,2),f(10,2)                          以g,h,i,j开头的长度为2的串的个数

                                      最后f(5,1),f(4,1),f(3,1),f(2,1),f(1,1)                      以l,m,n开头的长度为1的串的个数

把以上相加后还需要加1,求出本字符串的序

上述思想分析转自http://hi.baidu.com/hk2305621/item/36778b5156849eded48bacc7(为了节省打字时间)

代码实现如下:

#include <stdio.h>
#include <string.h>
#define MAX 20

//以第i个字符开头长度不超过k的升序字符串个数
int f(int i, int k)
{
int j;
int sum = 0;
if (k == 1) {
return 1;
}
else if (k > 1 && k <= 26) {
for (j = i+1; j <= 26; j++) {
sum += f(j, k-1);
}
return sum;
}
else {
printf("error\n");
return 0;
}
}

//长度不超过k的升序字符串总个数
int g(int k)
{
int i;
int sum = 0;
for (i = 1; i<= 26; i++) {
sum += f(i, k);
}
return sum;
}

int sum(char *str)
{
int total = 0;
int len = strlen(str);
int i;
for (i = 1; i < len; i++) {
total += g(i);
}
int k;
for (k = 1; k < len; k++) {
char temp;
if (k == 1) {
temp = 1;
}
else {
temp = str[k-2] - 'a' + 2;
}
for (i = temp; i < str[k - 1] - 'a' + 1; i++) {
//此处为+2因为当输入串为ac时,只增加以b开始长度为1的串计数,i='c'-'a'+2,以b(2)开始,'c'-'a'+1-1结束
total += f(i, len - k + 1);
//开始错在少len-k少+1,这样,计算bf时len=2,k=1,计算以a开头的两位字符串时计算成了1位
}
}
char temp ;
if (k == 1) {
temp = 1;
}
else {
temp = str[k-2] - 'a' + 2;
}
for (i = temp; i <= str[k - 1] - 'a' + 1; i++) {
total += f(i, 1);
}
return total;
}

int main()
{
char input[MAX];
while(gets(input))
{
//int len = strlen(input);
//printf("%d : %d\n", f(input[0] - 'a' + 1, len), g(len));
printf("%d\n", sum(input));
}
return 0;
}

posted on 2013-03-08 22:47  愤怒的屎壳螂  阅读(228)  评论(0编辑  收藏  举报

导航