您的位置:首页 > 其它

字符串尾序列(阿里笔试题)

2012-09-07 18:39 85 查看
题目:定义rotate(str, i)为把str[i..n-1]和str[0..i-1]拼接而成的字符串,其中n为字符串的长度, 0 =< i < n。

例如,对于字符串str = “abace”

rotate(str, 0) = "abace";

rotate(str, 1) = "bacea";

rotate(str, 2) = "aceab";

rotate(str, 3) = "ceaba";

rotate(str, 4) = "eabac";

现在,将这些字符串排序得到:

abace

aceab

bacea

ceaba

eabac

将这些排序之后的字符串的尾部字符连接起来得到:ebaac,并称之为合法尾部序列lst;将排序之后的第一个字符串abace称为首字符串。现在,已知合法尾部序列lst,如何求首字符串?要求时间复杂度最低。

分析:

(1)如果将首字符连起来得到aabce,并称之为合法首部序列sb,那么sb一定和st排序之后的字符串相等。因此,可以由st得到sb。

a***e

a***b

b***a

c***a

e***c

(2)如果将原来的字符串首尾连接成一个环,那么st[i]一定出现在sb[i]的前面。因此,可以根据一个字符推出紧接其后的下一个字符

a<--e

a<--b

b<--a

c<--a

e<--c

其中"y<--x"表示“x出现的位置恰好在x的前面”关系。

(3)有一种情况需要特别考虑:a在原字符串中出现了多次,如何知道每个a后面的字符呢?例如,对于题目中的例子,可以用如下步骤构造首字符串:首先知道第一个字符为a,然后根据(2)推出的位置关系可以知道b<--a, c<--a,也就是说a后面出现的字符可能为b,也可能为c。那么如何确定到底是哪一个呢?换个角度思考,如果能建立合法首部序列中a和合法尾部序列中a之间的一一对应关系,那么就知道每个a后面的字符。

下面为另一重要性质:

对任一字符x,在排序好的旋转字符串集中,左边为x的旋转字符串按顺序排列如下(其中sk为除掉首字母剩下的字符串):

xs1

xs2

...

xsk

那么有s1<=s2<=..<=sk,据此可知最右端为x的旋转字符串按序排列如下:

s1x

s2x

...

skx

也就是说,左边第一次出现的x与右边第一次出现的x对应;左边第i次出现的x与右边第i次出现的x对应。因此得到了左右字符之间的一一对应关系。

对于题目中的例子,下面来看下如何构造首字符串:首先知道第一个字符为a,此a对应右出现的第一个字符a,因此可得a后面的字符为b;b后面的字符为a;这个a对应第2次出现的a,因此可得紧接着的字符为c;c后面的字符为e。所以得到首字符串为abace。

知道此分析思路,不难写出复杂度为O(n)的算法。(注:对合法尾序列st中的字符进行稳定排序)

代码如下:

#include<stdio.h>
#include<string.h>
#include<malloc.h>
typedef struct _node{
int index;
struct _node * next;
} Node;
typedef struct _head{
int num;
Node* first;
} Head;
typedef struct _index_node{
int index;
char ch;
} Index_node;
int main()
{
char st[1000];
scanf("%s", st);
int n = strlen(st);
Head* heads = (Head*)malloc(sizeof(Head) * 256);//256 buckets, each for one character
memset(heads, 0, sizeof(Head) * n);
Node* nodePool = (Node*)malloc(sizeof(Node) * n);//memory pool
int npos = 0;
int i;

for(i = 0; i < n; i++)//insert each character into the corresponding bucket
{
Node* ptr = nodePool + npos++;
ptr->index = i;
ptr->next = heads[st[i]].first;
heads[st[i]].first = ptr;
heads[st[i]].num++;
}
Index_node* inodes = (Index_node*)malloc(sizeof(Index_node) * n);
int pg = 0;
for(i = 0; i < 256; i++)//unfold the elements in the buckets linearly
{
pg += heads[i].num;
int pl = pg - 1;
while(heads[i].first)
{
inodes[pl].ch = i;
inodes[pl].index = heads[i].first->index;
Node* nptr = heads[i].first;
heads[i].first = heads[i].first->next;
pl--;
}
}

int j;
for(j = 0, i = 0; i < n; i++)//construct the first string
{
printf("%c", inodes[j].ch);
j = inodes[j].index;
}
printf("\n");
free(heads);
free(nodePool);
free(inodes);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐