最长回文子串

将一个很长的字符串,分割成一段一段的子字符串,子字符串都是回文字符串。有回文字符串就输出最长的,没有回文就输出一个一个的字符。
例如:
habbafgh

输出h,abba,f,g,h。

#include 
#include 
#include 

#define MAX 10001
int len, p[2 * MAX];
char str[2 * MAX], newstr[2 * MAX];

void change() {
	int i;
	newstr[0] = '@';
	newstr[1] = '#';
	for (i = 0; i < len; i++) {
		newstr[2 * i + 2] = str[i];
		newstr[2 * i + 3] = '#';
	}
	len = 2 * len + 2;
	newstr[2 * len + 2] = '\0';
	return;
}

void Manacher() {
	/*maxid最右下标边界, ans最长回文长度, id最右边界的回文中心下标*/
	int i, j, id, maxid = 0;

	for (i = 0; i < len; i++) {

		/*maxid > i,表明i元素出现在回文范围内
		 *取最小,为maxid-i时超出最右,反之包含
		 *maxid<=i,未出现回文,默认1*/
		p[i] = maxid > i ?
				p[2 * id - i] > maxid - i ? maxid - i : p[2 * id - i]:0;

		/*输出字符串是根据'\0'来判断是否结束的,不会管你数组是大小,
		 * 就是因为这样,才有可能造成越界以后读到别人的内存,一般的内存没关系,
		 * 但要是恰好读到操作系统的,就会报错了*/
		/*探索该下标结点的回文长度*/
		while (newstr[i + 1 + p[i]] == newstr[i - 1 - p[i]]) {
			p[i]++;
		}

		//记录最大边界,最大回文点下标
		if (p[i] + i > maxid) {
			maxid = p[i] + i;
			id = i;
		}

	}

	//记录最大回文长度
	int maxLen = 0;
	//最长回文中心下标
	int centerIndex = 0;
	for (i = 1; i < len; i++) {
		if (p[i] > maxLen) {
			maxLen = p[i];
			centerIndex = i;
		}
	}

	//无回文
	if (maxLen == 1) {
		for (i = 0; i < strlen(str); i++) {
			if (i != 0) {
				printf(",");
			}
			printf("%3c", str[i]);
		}
	} else {
		//存在回文
		int start = (centerIndex - 1 - maxLen) / 2;
		for (i = 0; i < start; i++) {
			if (i != 0) {
				printf(",");
			}

			printf("%3c", str[i]);

			if (i == start - 1) {
				printf(",");
			}
		}

		for (i = (centerIndex - 1 - maxLen) / 2, j = 0; j < maxLen; i++, j++) {
			printf("%3c", str[i]);
		}

		for (; i < strlen(str); i++) {
			printf(",");
			printf("%3c", str[i]);
		}
	}

	str[j] = '\0';

	return;
}

int main(void) {
	strcpy(str, "habbafgh");
	len = strlen(str);
	change();
	Manacher();
//	puts(str);
	return EXIT_SUCCESS;
}


你可能感兴趣的:(最长回文子串,算法-字符串)