最长回文子串 leetcode-5

 

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:

Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example 2:

Input: "cbbd"
Output: "bb"

 

解法1:DP

dp[i][j] = 1,示i到j是回文子串。

$$ dp[i][j]=\left\{ \begin{array}{rcl} 1 & & {j-i = 1 , s[i]==s[j]}\\ 1 & & {dp[i+1][j-1]=1,s[i]==s[j],i-j>1}\\ 0 & & {else} \end{array} \right. $$

即两个相连的是回文子串;

dp[i+1][j-1]是小范围的回文子串的话,左右扩充且左右扩充的想等的也是回文子串;

#include<string>
#include<vector>
#include<iostream>
using namespace std;
class max_string
{
public:
	string longestPalindrome(string s) {
		vector<vector<int>> array(s.length(), vector<int>(s.length()));
		/*for (int i = 0; i < s.length; ++i) {
			array[i].resize(s.length);
		}*/
		int max = 1;
		int left = 0;
		for (int i = 0; i < s.length(); ++i) {
			array[i][i] = 1;
			for (int j = 0; j < i; ++j) {
				if (i - j == 1&&s[i]==s[j])
					array[j][i] = 1;
				if (i - j > 1 && array[j + 1][i - 1]==1 && s[i] == s[j])
					array[j][i] = 1;
				if (array[j][i] == 1 && i - j + 1> max) {
					max = i-j+1;
					left = j;
				}
			}
		}
	return s.substr(left, max);
	}
};

 

解法2:Manacher Algorithm (马拉车算法)

为了解决奇回文和偶回文的分别讨论,在字符串插入#解决,因为n个字符,需要插入n+1个。

然后为了解决越界在头插入$,且末尾包含\0,所以还是奇数。

比如原字符串: s =”abbaTNTabcba” 
插入字符之后:sNew= “$#a#b#b#a#T#N#T#a#b#c#b#a#

p[i]为第i个字符的回文半径。1代表仅包括自己。

解决思路:计算所有字符的回文半径,通过最多的来确定最长回文。

分两种情况计算回文半径:

第一种:i<mx

id为最大回文中心,mx为半径打到最远,i为当前下标,j为对称下标。因为id-j = i - id,所以 j = 2*id -i。

根据对称性,i的半径应该等于j的半径,当i的半径覆盖的区域没有超过mx的时候,p[i] = p[j];

如果超过了,那就暴力计算吧。

第二种:i>=mx

暴力计算。

 

#pragma once
#include<string>
#include<vector>
using namespace std;
class malache_maxstring
{
public:
	string longestPalindrome(string s) {
		string s_new = "$#";
		string s_out;
		for (auto i = 0; i < s.length(); ++i) {
			s_new += s[i];
			s_new += '#';
		}

		int max_len = 0;
		int id = 0;
		int mx = 0;
		vector<int> p(s_new.length(), 0);

		for (int i = 1; i < s_new.length(); ++i) {
			if (i < mx) {
				if (mx - i >= p[2 * id - i])
					p[i] = p[2 * id - i];
				if (mx - i < p[2 * id - i]) {
					for (int j = 1; i + j <= s_new.length(); ++j) {
						if (i + j == s_new.length()) {
							p[i] = j;
							if (j >= max_len) {
								id = i;
								max_len = j;
								mx = i + j - 1;
								s_out = s.substr((id - max_len) / 2, max_len - 1);
							}
						}
						else {
							if (s_new[i + j] == s_new[i - j])
								continue;
							else {
								p[i] = j;
								if (j >= max_len) {
									id = i;
									max_len = j;
									mx = i + j - 1;
									s_out = s.substr((id - max_len) / 2, max_len - 1);
								}
								break;
							}
						}
					}
				}
			}
			else {
				for (int j = 1; i + j <= s_new.length(); ++j) {
					if (i + j == s_new.length()) {
						p[i] = j;
						if (j >= max_len) {
							id = i;
							max_len = j;
							mx = i + j - 1;
							s_out = s.substr((id - max_len) / 2, max_len - 1);
						}
					}
					else {
						if (s_new[i + j] == s_new[i - j])
							continue;
						else {
							p[i] = j;
							if (j >= max_len) {
								id = i;
								max_len = j;
								mx = i + j - 1;
								s_out = s.substr((id - max_len) / 2, max_len - 1);
							}
							break;
						}
					}
				}
			}
		}
		return s_out;
	}
};


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值