回文串就是正度和反读都是一样的字符串
例如:
第3位为中心: c a b a d a b a e
第5位为中心: c a b a d a b a e
使用中心扩展算法
我们已经知道了第3位为中心的a b a和第5位为中心的a b a d a b a是回文,那么判断第7位为中心的回文串的时候,由于回文的特性,就能够知道2-4和6-8对称
1. c a b a d a b a e 2-4位与6-8对称
2. c a b a d a b a e 2-4位是回文
3. c a b a d a b a e 推断6-8位也是回文
以第6位为中心,由于第4位的回文长度是1,所以它也只能是1,不需要再扩展区判断了
以第7位为中心的回文串计算,由之前分析已经知道最小长度是3了,而且从5位的回文中心来看,我们只知道第8位是什么,到是具体第九位是什么,根据之前的信息我们无法得知,因此需要进行中心扩展
整个算法的颗星就是已知回文的右边界,只要在这个右边界的羽翼下,就有已知信息判断
算法步骤:
1.对字符串预处理,因为字符串可能为偶数,加入特殊符号#
2.然后遍历字符串,用一个数组来记录以该字符串为中心的回文长度,为了方便计算,在数组中存放记录长度的一半
3.每一次遍历字符串,如果该字符串在已知回文串最右边界的覆蓋下,那么就计算其相对右边界回文串中心对称的位置,得出已知回文串的长度;
4.判断该长度和右边界,如果达到右边界,那么需要进行中心扩展.当然,如果第3步该字符没有在右边界的覆蓋下,则直接进行中心扩展,进行中心扩展的同时更新右边界.
5.去掉特殊符号
代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Solution
{
class Program
{
static void Main(string[] args)
{
string s = "cabadabae";
s = LongestPalindrome(s);
Console.WriteLine(s);
Console.ReadKey();
}
static string LongestPalindrome(string s)
{
//1.0 预处理字符串
string str = PreHandleString(s);
//2.1 获取字符串的长度
int len = str.Length;
//2.2 右边界
int rightSide = 0;
//2.3 右边界对应的回文中心
int rightCenter = 0;
//2.4 回文的最长长度
int longest = 0;
//2.5 记录回文中心
int center = 0;
//2.6 用于记录以该字符为中心的长度的一半
int[] halfLenArr = new int[len];
//3.0 进行循环字符串
for (int i = 0; i < len; i++)
{
//是否需要中心扩展
bool needCal = true;
//3.1 判断是不是在右边界之内
if (rightSide > i)
{
//根据回文特性计算
int leftCenter = 2 * rightCenter - i;
halfLenArr[i] = halfLenArr[leftCenter];
//如果超过了右边界,进行调整
if (halfLenArr[i] + i > rightSide)
{
halfLenArr[i] = rightSide - i;
}
//如果根据已知条件计算得出的最长回文小于右边界,则不需要扩展
if (halfLenArr[leftCenter] + i < rightSide)
{
needCal = false;
}
}
if (needCal)
{
//3.2 由中心向两边扩展判断
while (i - 1 - halfLenArr[i] >= 0 && i + 1 + halfLenArr[i] < len)
{
if (str[i - 1 - halfLenArr[i]] == str[i + 1 + halfLenArr[i]])
{
halfLenArr[i]++;
}
else
{
//两边的值不同,跳出循环
break;
}
}
//3.3 更新回文中心以及右边界的值
rightCenter = i;
rightSide = i + halfLenArr[i];
//当前回文长度与最长回文长度做判断
if (halfLenArr[i] > longest)
{
//大于时,更新最长长度和回文中心
longest = halfLenArr[i];
center = i;
}
}
}
//4.0 去掉特殊字符串(去掉#)
StringBuilder sb = new StringBuilder();
for (int i = center - longest + 1; i <= center + longest; i += 2)
{
sb.Append(str[i]);
}
return sb.ToString();
}
/// <summary>
/// 预处理字符串
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private static string PreHandleString(string s)
{
StringBuilder sb = new StringBuilder();
sb.Append("#");
for (int i = 0; i < s.Length; i++)
{
sb.Append(s[i]);
sb.Append("#");
}
return sb.ToString();
}
}
}