【LeetCode 214】最长回文子串

题目链接:


https://leetcode.com/problems/shortest-palindrome/



题目描述:

给一个字符串s, 求在其前方添加最少的字符使添加后的s是回文串,并返回该回文串。

例如:

输入:1221abc

输出:cba1221abc


输入:121abc

输出:cba121abc



思路:

其实就是求从第一个字母开始,满足最长的回文串。

s = 最长从第一个字母开始的回文串 + 尾巴

ans = 尾巴的逆序 + s

所以,问题转化为求s的最长子回文串



最长回文字串:

暴力法:

定中心,从中心+-0开始 到两端扩展,判断是否回文串,O(n^2),超时

Manacher算法:

 从左到右边定中心,从中心+-p[中心]开始向两端扩展, 时间复杂度O(n), 详见前一篇博客 【最长回文子串】Manache算法


回文串两种形式,统一为一种形式

因为回文串有两种形式,

121,奇数

1221,偶数

通过加入符号可以都转换为奇数的情况

121      ->     #1#2#1

1221    ->    #1#2#2#1#

用转换后的字符换进行处理,求完后再求出,在原字符串的起点,长度即可


实现:

#include<string>
#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
    string shortestPalindrome(string s) {
		int i, j;
		string s2 = "#";
		for (i = 0; i < s.length(); i++) {
			s2 += s.at(i);
			s2 += "#";
		}
		vector<int> p = manacher(s2);
		
		int cen = 0;
		for (i = 0; i < p.size(); i++) {
			if(i - p[i] == 0) {
				cen = i;
			}
		}

		int maxL = p[cen];
		string head = "";
		for (j = s.length() - 1; j >= maxL; j--) {
			head += s.at(j);				
		}
		s = head + s;
		return s;
    }

	vector<int> manacher(string s) {
		int l, r;
		int len = s.length();
		int cen = 0;
		vector<int> p;
		p.push_back(0);

		for (r = 1; r < len; r++) {
			// printf("cen = %d, pcen = %d, r = %d\n", cen, p[cen], r);
			p.push_back(0);
			int cenR = cen + p[cen];
			if (r <= cenR) {
				l = 2 * cen - r;
				p[r] = p[l] < cenR - r ? p[l] : cenR - r;
			} else {
				p[r] = 0;
			}

			// 这里是关键,如果从r为中心长度为0开始向两边扩展,则复杂度为O(n^2), 这里从p[r]开始扩展
			while((r-p[r]-1>=0) && (r+p[r]+1<len) && (s.at(r - p[r] -1) == s.at(r + p[r] + 1))) p[r]++;

			if (r + p[r] > cenR) {
				cen = r;
			}
		}

		//cout << s << endl;
		//int i;
		//for (i = 0; i < len; i++) {
		//	printf("%d ", p[i]);
		//} printf("\n");
		return p;
	}
};
int main() {
	Solution s;
	string ans = s.shortestPalindrome("77777777777777777777777777777777777777771");
	cout << ans << endl;
	return 0;
}


你可能感兴趣的:(【LeetCode 214】最长回文子串)