214. Shortest Palindrome

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

For example:

Given "aacecaaa", return "aaacecaaa".

Given "abcd", return "dcbabcd".

Credits:
Special thanks to @ifanchu for adding this problem and creating all test cases. Thanks to @Freezen for additional test cases.

Subscribe to see which companies asked this question.


在字符串前面加字符,使得字符串变成回文字符串,要求加的字符尽量少,返回由源字符串变成的最短的回文字符串。这个问题可以转化为求字符串包含开头部分的最长的回文子字符串的长度,求得之后补剩下的字符即可。这里的实现用到了kmp算法的思想。

首先kmp算法的想法是对需要查找的字符串进行预处理,求出一张前缀匹配表(自己瞎命名的),对每个位置,记录下以其为结尾的某子字符串在字符串前缀重复的长度,这样如果某个位置匹配不成功,就不用返回到最开头的位置重新开始。比如"ABAB",对应的表示“0012”。对于某一个位置的计算方法是,根据前一个字符对应的前缀长度len,找出在前缀中相应的位置,判断当前位置的字符和前缀位置的字符(s[len],也就是前一个字符对应的前缀位置的下一个字符)是否相等,相等的话说明还是前缀,长度加长1保存起来;不然的话继续往前找。以一个例子说明,对于字符串"ABABABABC",前面四个对应的表是“0012”,对第五个字符‘A’,前面的‘B’对应的值是2,取得s[2]为‘A’,与s[4]相等,所以table[4]=table[1]+1=1;同理table[5]=table[2]+1=2,table[6]=table[3]+1=3,table[7]=table[4]+1=4,所以现在的表是“00121234”。到了第九个字符‘C’,首先前面的‘B’对应的值是4,而s[4]为‘A’,与‘C’不相等,继续往前找(因为前面可能有短一点的前缀),对于位置4的前一个位置3,table[3]为2,取得s[2]为‘A’,也是不相等;继续往前找,位置2的前一个位置1,table[1]为0,说明了已经没有适合的前缀了。所以令table[8]=0。

把kmp的想法应用在寻找最长的前缀回文子字符串。把原字符串倒转拼接在原字符串后面,以一个字符分隔开(随便!@¥#……¥%都行)。然后也是求一张前缀匹配表。最长的前缀回文子字符串长度就是表的最后一项。比如“aacecaaa”,拼接后“aacecaaa$aaacecaa”,对应的表是“01000121201234567”,最长的前缀回文子字符串长度就是7.


代码:

class Solution {
public:
	string shortestPalindrome(string s)
	{
		if(s.empty()) return s;
		string t = s;
		reverse(t.begin(), t.end());
		get_table(s + "$" + t);
		//for(auto item:table) cout << item << endl;
		
		return t.substr(0, s.size() - table.back()) + s;
	}
private:
	vector<int>table;
	void get_table(string s)
	{
		table.resize(s.size(), 0);
		for(int i = 1; i < s.size(); ++i)
		{
			int prev = i - 1;
			while(prev >= 0 && s[i] != s[table[prev]])
			{
				prev = table[prev] - 1;
			}
			if(prev >= 0) table[i] = table[prev] + 1;
		}
	}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值