尾序列问题

问题:

在《编程珠玑》一书中,提到字符串旋转问题,比如有字符串ab旋转得到字符串ba,那么可以通过(a'b')'得到,其中“ ' ”表示整个字符串旋转。

在这个问题中,比如"abace"通过在不同位置旋转,可以得到"eabac","ceaba","aceab","bacea",将这些字符串按照字典排序,得到:

abace

aceab

bacea

ceaba

eabac

这样得到尾序列为"ebaac"。问题是给定尾序列"ebaac"如何得到字典排序的首字符串?

分析:

根据尾序列,我们可以得到字符串中所有的字母,然后对字母进行排序,可以得到所有字符串的首字母,由于在旋转过程中,存在这样的性质,"a***e"通过右移位,我们可以得到"ea***",因此,字母"e"后面一定是"a",这是一个重要的性质。

a***e

a***b

b***a

c***a

e***c

但是如果存在重复字母呢?比如

b***a

c***a

那么"a"后面可以是"b"和"c",但是我们根据字典排序知道,"a"开头的字符串,靠在前面的字符串后面跟的一定是小的字母,所以第一个"a"开头的字符串后面接的一定是"b",第二个"a"开头的字符串后面一定接的"c",那么确定第二个字母,如何确定第三个字母呢?同样的,确定"b"后,我们根据以"b"结尾的行"a***b",右移一位,得到"ba***",知道"b"后面的字母一定是"a",从而确定b后面是a,然后再根据这个''a"得到后面的"c",由此类推。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct A
{
	int ind;		//记录下标,这个非常重要
	char ch;
};
int comp(const void * x, const void *y)
{
	return (((struct A *) x)->ch > ((struct A *) y)->ch
			|| ((struct A *) x)->ch == ((struct A *) y)->ch	//如果字母相同,下标小的排在前面
					&& ((struct A *) x)->ind > ((struct A *) y)->ind);
}
int main()
{
	char s[50] = "ebaac", f[50];
	int i, j, len;
	struct A a[50];
	scanf("%s", s);
	len = strlen(s);
	for (i = 0; i < len; i++)
	{
		a[i].ind = i;
		a[i].ch = s[i];
	}

	printf("origin:%d:%s\n", len, s);
	qsort(a, len, sizeof(struct A), comp);		//进行快排
	for (i = 0; i < len; i++)
	{
		printf("%d, %c\n", a[i].ind, a[i].ch);
	}
	for (i = 0, j = 0; i < len; i++)
	{
		f[i] = a[j].ch;
		j = a[j].ind;
	}
	f[len] = '\0';
	printf("%s\n", f);

	return 0;
}

注意:这里使用下标保存行信息,如下所示:

2 a***e 0
3 a***b 1
1 b***a 2
4 c***a 3
0 e***c 4

总结:

注意分析问题的性质,善于利用性质进行求解。


你可能感兴趣的:(编程,c,struct)