字符串尾序列(阿里笔试题)
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中的字符进行稳定排序)
代码如下:
例如,对于字符串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; }
相关文章推荐
- 2015年阿里在线笔试题:求两个字符串的最大公共子序列长度的C语言解法
- [阿里2015校招笔试]求字符串query和text最长连续字母序列的长度
- 阿里笔试题:求两个子序列的最大连续子序列
- 2016/9/9阿里笔试编程题-字符串的查找替换
- 阿里2018校招内推笔试题-字符串切分
- 求两个字符串的最大公共长度 看到的一道阿里笔试题
- 阿里笔试题:求两个子序列的最大连续子序列
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
- 最长连续字母序列的长度(阿里2015在线研发工程师笔试题)
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
- 求两个字符串公共子序列的最大长度(参考阿里巴巴2015研发笔试)(简单)
- 阿里测试开发笔试题--字符串相关知识
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
- 将字符串划分为单词—阿里2017笔试编程题
- 阿里笔试题:求两个子序列的最大连续子序列
- 2014年阿里研发笔试题:在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度
- 阿里校招笔试——给定一个字符串S和有效单词的字典D,请确定可以插入到S中的最小空格数,使得最终的字符串完全由D中的有效单词组成,并输出解。
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
- 笔试算法题(35):最长递增子序列 & 判定一个字符串是否可由另一个字符串旋转得到