1. 题⽬链接:5.最⻓回⽂⼦串
2. 题⽬描述:
3. 解法(中⼼扩散):
算法思路:
枚举每⼀个可能的⼦串⾮常费时,有没有⽐较简单⼀点的⽅法呢?
对于⼀个⼦串⽽⾔,如果它是回⽂串,并且⻓度⼤于2,那么将它⾸尾的两个字⺟去除之后,它仍然是 个回⽂串。如此这样去除,⼀直除到⻓度⼩于等于2时呢?⻓度为1的,⾃⾝与⾃⾝就构成回⽂;⽽ ⻓度为2的,就要判断这两个字符是否相等了。
从这个性质可以反推出来,从回⽂串的中⼼开始,往左读和往右读也是⼀样的。那么,是否可以枚举 回⽂串的中⼼呢?
从中⼼向两边扩展,如果两边的字⺟相同,我们就可以继续扩展;如果不同,我们就停⽌扩展。这样 只需要⼀层for循环,我们就可以完成先前两层for循环的⼯作量。
C++算法代码:
class Solution
{
public:
string longestPalindrome(string s)
{
string answer; //答案
int max_num=0; //最长大小
int begin=0; //起始位置
//遍历每一位置
for(int i=0;i<s.size();i++)
{
//寻找奇数长度
int left=i,right=i;
//退出循环时左右都各超出了一位
while(left >= 0 && right < s.size() && s[left] == s[right])
{
left--;
right++;
}
if(right - left - 1 > max_num)
{
begin = left+1 ;
max_num = right - left - 1;
}
//寻找偶数长度
left=i,right=i+1;
//退出循环时左右都各超出了一位
while(left >= 0 && right < s.size() && s[left] == s[right])
{
left--;
right++;
}
if(right - left - 1 > max_num)
{
begin = left+1 ;
max_num = right - left - 1;
}
}
return s.substr(begin,max_num);
}
};
Java算法代码:
class Solution
{
public String longestPalindrome(String s)
{
int begin = 0, len = 0, n = s.length();
for (int i = 0; i < n; i++) // 固定所有的中间点
{
// 先扩展奇数⻓度的⼦串
int left = i, right = i;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right))
{
left--;
right++;
}
if (right - left - 1 > len)
{
begin = left + 1;
len = right - left - 1;
}
// 扩展偶数⻓度
left = i; right = i + 1;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right))
{
left--;
right++;
}
if (right - left - 1 > len)
{
begin = left + 1;
len = right - left - 1;
}
}
return s.substring(begin, begin + len);
}
}