尾序列問題

問題:

在《編程珠璣》一書中,提到字符串旋轉問題,比如有字符串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

總結:

注意分析問題的性質,善於利用性質進行求解。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章