最长回文子串解法详解

【算法专题--回文】最长回文子串 -- 高频面试题(图文详解,小白一看就懂!!) 最长回文子串 这道题,可以说是--回文专题 --,最经典的一道题,也是在面试中频率最高的一道题目,通常在面试中,面试官可能会从多个方面考察这道题目,所以大家需要对这道题目非常熟悉哦!! 本片博客就来详细的讲讲解一下 最长回文子串 的实现方法,让我们的面试变的更加顺利!!! 阅读详情

回文串,就是指正读和反读都一样的字符串,比如"level"或者"noon"等等。

那么,如何求一个字符串的最长回文子串(Longest Palindromic Substring)?这里我们有多种解法。

解法一:暴力法

暴力解法就是直接枚举所有子串,对每个子串判断是否为回文,时间复杂度为 O(n3) 。

这是最糟糕的方法,相信面试官问你这个问题,绝对不是想要这个答案。

string findLongestPalindrome(string &s)
{
	int length=s.size();//字符串长度
	int maxlength=0;//最长回文字符串长度
	int start;//最长回文字符串起始地址
	for(int i=0;i<length;i++)//起始地址
		for(int j=i+1;j<length;j++)//结束地址
		{
			int tmp1,tmp2;
			for(tmp1=i,tmp2=j;tmp1<tmp2;tmp1++,tmp2--)//判断是不是回文
			{
				if(s.at(tmp1)!=s.at(tmp2))
					break;
			}
			if(tmp1>=tmp2&&j-i>maxlength)
			{
				maxlength=j-i+1;
				start=i;
			}
		}
		if(maxlength>0)
			return s.substr(start,maxlength);//求子串
		return NULL;
}

解法二:动态规划法 O(n2)

动态规划法是在暴力解法上进行的优化。通过记录一些我们需要的东西,来避免暴力解法中很多重复的判断。

假设  dp[i][j]  表示子串  s[i…j]  是否是回文,那么对于动态规划表  dp  的打表方式如下:


C++代码如下

string longestPalindrome(string s) {
	int len = s.size();
	if(len <= 1) return s;
	// 动态规划表,全部初始化为true
	vector<vector<bool>> dp(len, vector<bool>(len, true));

	int start = 0, maxlen = 0;
	for(int k=2; k<=len; ++k) {    // 枚举子串的长度
		for(int i=0; i<=len-k; ++i) {  // 枚举子串起始位置
			int j = i+k-1;
			if(s[i] == s[j] && dp[i+1][j-1])
			{
				dp[i][j] = true;
				start = i;      // 记录回文子串的起点和长度
				maxlen = k;
			}
		}
	}

	return s.substr(start, maxlen);
}

回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串。这样最长回文子串就能分解成一系列子问题了。这样需要额外的空间O(N^2),算法复杂度也是O(N^2)。

首先定义状态方程和转移方程:

P[i,j]=0表示子串[i,j]不是回文串。P[i,j]=1表示子串[i,j]是回文串。

P[i,i]=1

P[i,j]  = P[i+1,j-1],   if(s[i]==s[j])

         = 0 ,              if(s[i]!=s[j])

string findLongestPalindrome(string &s)
{
	const int length=s.size();
	int maxlength=0;
	int start;
	bool P[50][50]={false};
	for(int i=0;i<length;i++)//初始化准备
	{
		P[i][i]=true;
		if(i<length-1&&s.at(i)==s.at(i+1))
		{
			P[i][i+1]=true;
			start=i;
			maxlength=2;
		}
	}
	for(int len=3;len<length;len++)//子串长度
		for(int i=0;i<=length-len;i++)//子串起始地址
		{
			int j=i+len-1;//子串结束地址
			if(P[i+1][j-1]&&s.at(i)==s.at(j))
			{
				P[i][j]=true;
				maxlength=len;
				start=i;
			}
		}
	if(maxlength>=2)
		return s.substr(start,maxlength);
	return NULL;
}

解法三:中心扩展法 O(n2)

这个算法思想其实很简单,就是对给定的字符串S,分别以该字符串S中的每一个字符 c 为中心,向两边扩展,记录下以字符 c 为中心的回文子串的长度。时间复杂度为 O(n2) ,空间复杂度仅为 O(1) 。

但有一点需要注意的是,回文的情况可能是 a b a,也可能是 a b b a。

// 分别向左右扩展,返回扩展后的字符串
string expand(string s, int left, int right) {
	int len = s.size();
	while (left>=0 && right<len && s[left] == s[right]) 
	{
		left--;
		right++;
	}
	return s.substr(left+1, right-left-1);
}

// 求最长回文子串
string longestPalindrome(string s) {
	int len = s.size();
	if(len<=1) return s;

	string longest;
	for (int i=0; i<len-1; i++) 
	{
		string p1 = expand(s, i, i);  // 奇数
		if (p1.size() > longest.size())
			longest = p1;

		string p2 = expand(s, i, i+1);  // 偶数
		if (p2.size() > longest.size())
			longest = p2;
	}
	return longest;
}
string findLongestPalindrome(string &s)
{
	const int length=s.size();
	int maxlength=0;
	int start;

	for(int i=0;i<length;i++)//长度为奇数
	{
		int j=i-1,k=i+1;
		while(j>=0&&k<length&&s.at(j)==s.at(k))
		{
			if(k-j+1>maxlength)
			{
				maxlength=k-j+1;
				start=j;
			}
			j--;
			k++;
		}
	}

	for(int i=0;i<length;i++)//长度为偶数
	{
		int j=i,k=i+1;
		while(j>=0&&k<length&&s.at(j)==s.at(k))
		{
			if(k-j+1>maxlength)
			{
				maxlength=k-j+1;
				start=j;
			}
			j--;
			k++;
		}
	}
	if(maxlength>0)
		return s.substr(start,maxlength);
	return NULL;
}

另外,据说还有一个很巧妙的算法,叫Manacher算法,可以在  O(n)  的时间复杂度里求出最长回文子串。

Manacher法


Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是就在里面添加特殊字符。我是添加了“#”,使abba变为a#b#b#a。这个算法就是利用已有回文串的对称性来计算的,具体算法复杂度为O(N),我没看出来,因为有两个嵌套的for循环。
具体原理参考这里。 测试代码中没过滤掉“#”。
Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串。其算法的基本原理就是利用已知回文串的左半部分来推导右半部分。
首先,在字符串s中,用rad[i]表示第i个字符的回文半径,即rad[i]尽可能大,且满足:
s[i-rad[i],i-1]==s[i+1,i+rad[i]]
很明显,求出了所有的rad,就求出了所有的长度为奇数的回文子串.
至于偶数的怎么求,最后再讲.
假设现在求出了rad[1..i-1],现在要求后面的rad值,并且通过前面的操作,得知了当前字符i的rad值至少为j.现在通过试图扩大j来扫描,求出了rad[i].再假设现在有个指针k,从1循环到rad[i],试图通过某些手段来求出[i+1,i+rad[i]]的rad值.
根据定义,黑色的部分是一个回文子串,两段红色的区间全等.
因为之前已经求出了rad[i-k],所以直接用它.有3种情况:


①rad[i]-k<rad[i-k]
如图,rad[i-k]的范围为青色.因为黑色的部分是回文的,且青色的部分超过了黑色的部分,所以rad[i+k]肯定至少为rad[i]-k,即橙色的部分.那橙色以外的部分就不是了吗?这是肯定的.因为如果橙色以外的部分也是回文的,那么根据青色和红色部分的关系,可以证明黑色部分再往外延伸一点也是一个回文子串,这肯定不可能,因此rad[i+k]=rad[i]-k.为了方便下文,这里的rad[i+k]=rad[i]-k=min(rad[i]-k,rad[i-k]).


②rad[i]-k>rad[i-k]
如图,rad[i-k]的范围为青色.因为黑色的部分是回文的,且青色的部分在黑色的部分里面,根据定义,很容易得出:rad[i+k]=rad[i-k].为了方便下文,这里的rad[i+k]=rad[i-k]=min(rad[i]-k,rad[i-k]).
根据上面两种情况,可以得出结论:当rad[i]-k!=rad[i-k]的时候,rad[i+k]=min(rad[i]-k,rad[i-k]).
注意:当rad[i]-k==rad[i-k]的时候,就不同了,这是第三种情况:


如图,通过和第一种情况对比之后会发现,因为青色的部分没有超出黑色的部分,所以即使橙色的部分全等,也无法像第一种情况一样引出矛盾,因此橙色的部分是有可能全等的,但是,根据已知的信息,我们不知道橙色的部分是多长,因此就把i指针移到i+k的位置,j=rad[i-k](因为它的rad值至少为rad[i-k]),等下次循环的时候再做了.
整个算法就这样.
至于时间复杂度为什么是O(n),我已经证明了,但很难说清楚.所以自己体会吧.
上文还留有一个问题,就是这样只能算出奇数长度的回文子串,偶数的就不行.怎么办呢?有一种直接但比较笨的方法,就是做两遍(因为两个程序是差不多的,只是rad值的意义和一些下标变了而已).但是写两个差不多的程序是很痛苦的,而且容易错.所以一种比较好的方法就是在原来的串中每两个字符之间加入一个特殊字符,再做.如:aabbaca,把它变成(#a#a#b#b#a#c#a#),左右的括号是为了使得算法不至于越界。这样的话,无论原来的回文子串长度是偶数还是奇数,现在都变成奇数了.

#define min(x, y) ((x)<(y)?(x):(y))
#define max(x, y) ((x)<(y)?(y):(x))
string findLongestPalindrome3(string s)
{
	int length=s.size();
	for(int i=0,k=1;i<length-1;i++)//给字符串添加 #
	{
		s.insert(k,"#");
		k=k+2;
	}
	length=length*2-1;//添加#后字符串长度
	int *rad=new int[length]();
	rad[0]=0;
	for(int i=1,j=1,k;i<length;i=i+k)
	{
		while(i-j>=0&&i+j<length&&s.at(i-j)==s.at(i+j))
			j++;
		rad[i]=j-1;
		for(k=1;k<=rad[i]&&rad[i-k]!=rad[i]-k;k++)//镜像,遇到rad[i-k]=rad[i]-k停止,这时不用从j=1开始比较
			rad[i+k]=min(rad[i-k],rad[i]-k);

		j=max(j-k,0);//更新j
	}
	int max=0;
	int center;
	for(int i=0;i<length;i++)
	{
		if(rad[i]>max)
		{
			max=rad[i];
			center=i;
		}
	}
	return s.substr(center-max,2*max+1);
}

算法导论,O(n)求解回文串

回文串定义:“回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。回文子串,顾名思义,即字符串中满足回文性质的子串。
经常有一些题目围绕回文子串进行讨论,比如POJ3974最长回文,求最长回文子串的长度。朴素算法是依次以每一个字符为中心向两侧进行扩展,显然这个复杂度是O(N^2)的,
关于字符串的题目常用的算法有KMP、后缀数组、AC 自动机,这道题目利用扩展KMP可以解答,其时间复杂度也很快O(N*logN)。但是,今天笔者介绍一个专门针对回文子串的算法,其时间复杂度为O(n),这就是manacher 算法。
大家都知道,求回文串时需要判断其奇偶性,也就是求aba 和abba 的算法略有差距。然而,这个算法做了一个简单的处理,很巧妙地把奇数长度回文串与偶数长度回文串统一考虑,也就是在每个相邻的字符之间插入一个分隔符,串的首尾也要加,当然这个分隔符不能再原串中出现,一般可以用‘#’或者‘$’等字符。例如:
原串:abaab
新串:#a#b#a#a#b#
这样一来,原来的奇数长度回文串还是奇数长度,偶数长度的也变成以‘#’为中心奇数回文串了。
接下来就是算法的中心思想,用一个辅助数组P 记录以每个字符为中心的最长回文半径,也就是P[i]记录以Str[i]字符为中心的最长回文串半径。P[i]最小为1,此时回文串为Str[i]本身。
我们可以对上述例子写出其P 数组,如下
新串: # a # b # a # a # b #
P[] :      1 2 1 4 1 2 5 2 1 2 1
我们可以证明P[i]-1 就是以Str[i]为中心的回文串在原串当中的长度。
证明:
1、显然L=2*P[i]-1 即为新串中以Str[i]为中心最长回文串长度。
2、以Str[i]为中心的回文串一定是以#开头和结尾的,例如“#b#b#”或“#b#a#b#”所以L 减去最前或者最后的‘#’字符就是原串中长度 的二倍,即原串长度为(L-1)/2,化简的P[i]-1。得证。 依次从前往后求得P 数组就可以了,这里用到了DP(动态规划)的思想,也就是求P[i] 的时候,前面的P[]值已经得到了,我们利用回文串的特殊性质可以进行一个大大的优化。

先把核心代码贴上:

for (i = 0; i < len; i++)
{
     if (maxid > i)
	 {
         p[i] = min(p[2*id - i], maxid - i);
     }
     else
	 {
          p[i] = 1;
     }
     while (newstr[i+p[i]] == newstr[i-p[i]])
            p[i]++;
     if (p[i] + i > maxid)
	 {
         maxid = p[i] + i;
         id = i;
     }
     if (ans < p[i])
         ans = p[i];
}
为了防止求P[i]向两边扩展时可能数组越界,我们需要在数组最前面和最后面加一个特殊字符,令P[0]=‘$’最后位置默认为‘\0’不需要特殊处理。此外,我们用MaxId 变量记录在求i 之前的回文串中,延伸至最右端的位置,同时用id 记录取这个MaxId 的id 值。通过下面这句话,算法避免了很多没必要的重复匹配。

if (maxid > i)
{
    p[i] = min(p[2*id - i], maxid - i);
}
那么这句话是怎么得来的呢,其实就是利用了回文串的对称性,如下图,


j=2*id-1 即为i 关于id 的对称点,根据对称性,P[j]的回文串也是可以对称到i 这边的,但是如果P[j]的回文串对称过来以后超过MaxId 的话,超出部分就不能对称过来了,如下图,


所以这里P[i]为的下限为两者中的较小者,p[i]=Min(p[2*id-i],MaxId-i)。算法的有效比较次数为MaxId 次,所以说这个算法的时间复杂度为O(n)。

具体代码,求解最长回文字符串的代码:
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int MAX = 100001;
int len, p[2*MAX];
char str[2*MAX], newstr[2*MAX];

void change()
{
     int i;
     newstr[0] = '@';
     newstr[1] = '#';
     for (i = 0; i < len; i++){
         newstr[2*i + 2] = str[i];
         newstr[2*i + 3] = '#';
     }
     newstr[2*len + 2] = '\0';
     return ;
}

void Manacher()
{
     int i, j, id, maxid = 0, ans = 1;
     len = 2 * len + 2;
     for (i = 0; i < len; i++){
         if (maxid > i){
             p[i] = min(p[2*id - i], maxid - i);
         }
         else{
              p[i] = 1;
         }
         while (newstr[i+p[i]] == newstr[i-p[i]])
                p[i]++;
         if (p[i] + i > maxid){
             maxid = p[i] + i;
             id = i;
         }
         if (ans < p[i])
             ans = p[i];
     }

     for (i = id, j = 0; i < id + ans; i++){
          if (newstr[i] != '#'){
              str[j] = newstr[i];
              j++;
          }
     }
     str[id+ans] = '\0';
     cout << ans - 1 << " " << str << endl;
     return ;
}

int main()
{
    while (scanf("%s", &str))
	{
          if (strcmp(str, "END") == 0)   break;
          len = strlen(str);
          change();
          Manacher();
    }
    return 0;
}

腾讯云运维工程师认证TCA--真题(最新2022.11) 解析:云原生应用的12要素,1.基准代码:一份基准代码,多份部署;解析:腾讯云主账号具备对其名下资源(包括存储桶)的最大权限,您虽然可以在存储桶策略中限制几乎所有操作,但主账号始终具备 PUT Bucket Policy 操作的权限,主账号调用该操作不检查存储桶策略。解析:瀑布模型将软件生命周期划分为制定计划、需求分析、软件设计、程序编写、软件测试和运行维护等六个基本活动,并且规定了它们自上而下、相互衔接的固定次序,如同瀑布流水,逐级下落。解答:云原生五大关键技术:微服务、容器化、DevOps、持续交付。 阅读详情

相关推荐

n8n 快速入门1:构建一个简单的工作流

n8n 快速入门指南

engchina的专栏 1万+

题解:最长回文子串(4种解法)

题目:最长回文子串 难度:中等 一、描述 二、题解: 2.1 暴力法(O(N^3)) 解释: 循环三次。第一次起始点循环;第二次终止点循环(从最右边开始到起始点为止);第三次起始点开始终止点结束,当两个值不相等时候跳出循环。只有完整进行第三次循环才满足回文串的条件。 class Solution: def longestPalindrome(self, s: str) -> str: max_ = 1 max_str = s[0] length

v-space的博客 2万+

【深度排查】VScode 远程 SSH 连接失败:从网络握手到服务部署的全链路诊断指南

本文详细解析了VScode远程SSH连接失败的常见原因及解决方案,从基础网络排查到SSH服务配置,再到VScode特有的问题处理。特别针对Ubuntu和TrueNAS系统提供了具体配置建议,帮助开发者快速解决'Could not establish connection'等连接问题,提升远程开发效率。

weixin_30301449的博客 445

笔试面试算法经典--最长回文子串

回文的定义正读和反读都相同的字符序列为“回文”,如“abba”、“abccba”是“回文”,“abcde”和“ababab”则不是“回文”。字符串的最长回文子串,是指一个字符串中包含的最长的回文子串。例如“1212134”的最长回文子串是“12121”。下面给出了三种求最长子串的方法。解法1(中心扩展法)时间复杂度O(n^2),空间复杂度为O(1)。中心扩展法的思路是,遍历到数组的某一个元素时,以这

有图有真相 4万+

Ambari 3.0.0 + BigTop 3.3.0 源码编译与集群部署指南(Kylin V10 / aarch64)

仅仅是针对“应用商店目录(Applications Catalog)”的一个外围附属子模块(它不是 YARN 监控大盘,不影响 YARN UI 网页的主体使用),我们可以采用。自带的 Node 二进制是 x86_64 版本,在 ARM64(aarch64)容器上无法执行(Exit value: 126)。:Ambari Server/Agent 使用 JDK 17,BigTop 大数据组件(Hadoop/HBase/Spark 等)使用 JDK 8。,源码中包含 x86 特定的原生二进制文件。

amumu1992的博客 480

别再手动算K值了!ZEMAX中两种锥透镜建模方法详解(标准面 vs. 轴锥面)

本文详细解析了ZEMAX中锥透镜的两种建模方法:标准面与轴锥面。通过对比两者的精度、计算效率和适用场景,帮助工程师在激光整形、光束匀化等应用中做出最优选择,并提供了参数设置和异常排查的实用技巧。

weixin_42548874的博客 319

最长回文子串(Longest Palindromic Substring)

最长回文子串(Longest Palindromic Substring)题目解析 题目 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: “babad” 输出: “bab” 注意: “aba” 也是一个有效答案。 示例 2: 输入: “cbbd” 输出: “bb” 解析 子串(substring):原始字符串的一个连续子集; 子序列(subsequence):原始字符串的一个子集; 区别:子串连续,子序列不必连续 一般处理: 先计算出子串的长度

qq_43232556的博客 4124

手把手教你用ESP32驱动MAX30102心率血氧传感器(含完整代码)

本文详细介绍了如何使用ESP32微控制器驱动MAX30102心率血氧传感器,构建智能健康监测系统。内容涵盖PPG原理、硬件连接、驱动配置、信号处理算法以及Web服务器数据可视化,提供完整代码实现,帮助开发者快速上手物联网健康设备开发。

weixin_29208077的博客 586

如何求一个字符串最长的回文子串 三种方法 思路详解

如题示例 输入:s = "ababa" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 一道算法题,肯定思路最先想到的肯定是暴力解法,也是最简单的, 方法一 : 暴力破解 思路:列举字符串所有的子串,判断是否为回文数,在返回其中最大的一个 (代码已经运行通过,放心食用!) 现在我来解释一下: 这个很简单,len是代表着字符串s的长度,这里就是判断一下如果s为null或者长度为1,直接返回s就是其最大回文数了。注意一下,length()是String内一个方法,返回字符串的.

m0_65725614的博客 1万+

15、人工智能社会学:关系视角下的机器相遇

本文探讨了将人工智能视为社会主体的可能性,提出了一种关系视角下的人工智能社会学。通过结合卢西亚娜·帕里西、艾伦·图灵和乔治·赫伯特·米德的理论,强调不确定性在人工智能运行中的核心地位,并分析了人工智能如何通过与社会环境的互动催生新奇性,从而拓展社会学的研究范畴。文章还讨论了人工智能对社会结构和社会互动的影响,以及其作为社会主体所带来的理论和实践意义,为未来人工智能社会学的发展提供了方向。

pea55的博客 72

【PG高可用】一 PostgreSQL高可用方案repmgr部署(非常详细)

repmgr安装部署

DBA之路的博客 7052

【LeetCode】5. 最长回文子串 动态规划、中心扩展、马拉车算法 多解法详解

给你一个字符串s,找到s中最长的回文子串。

Ekertree的博客 990

NLTK中WordNet与同义词处理

通过本教程,学习了如何使用NLTK中的WordNet进行自然语言处理任务。首先介绍了WordNet的基本概念及其在NLTK中的集成使用,接着讲解了如何查找同义词、反义词等词汇关系,并结合实际应用演示了语义相似性计算。这些技能在文本分析、情感分析、信息检索等场景中有广泛应用,可以帮助开发者构建更智能的自然语言处理系统。掌握这些基本操作后,可以进一步探索WordNet的其他高级功能,结合其他NLTK工具进行更复杂的语言分析。

Mr数据杨 471

【LeetCode #5 题解】 最长回文子串

【LeetCode #5 题解】 最长回文子串一、题目二、题解一:暴力查找法三、题解二: 一、题目 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2: 输入: "cbbd" 输出: "bb" 二、题解一:暴力查找法 虽然可以解决问题,但该方法耗时太久,不可取。 需要另找更快的方法 // 题解一: 最笨的方法,暴力查找法,当字串很大时,leetcode

|~~~热爱生活、努力学习的小伙汁~~~| 516

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

【Leetcode hot 100】5.最长回文子串

本文介绍了两种解决最长回文子串问题的算法:中心扩散法和动态规划法。中心扩散法从所有可能的回文中心向两边扩展验证,时间复杂度O(n²),空间复杂度O(1),实现简单高效。动态规划法利用dp数组记录子串回文状态,同样时间O(n²)但空间O(n²)。对比显示中心扩散法更优,适合实际应用;动态规划法有助于理解子问题分解思想。两种方法均能有效解决问题,可根据需求选择。

专注Java和MySQL领域知识分享 1002

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

LeetCode 5. 最长回文子串:动态规划详解(附完整可运行代码)

回文串:正读和反读都相同的字符串(如 "abcba"、"bb"),子串是连续的字符序列(区别于子序列)。定义二维布尔数组dp[i][j],表示字符串s中从索引i到索引j(闭区间[i, j])的子串是否为回文串。若:子串s[i..j]是回文串若:子串s[i..j]不是回文串本文通过动态规划方法详细讲解了 LeetCode 5. 最长回文子串的求解过程,核心是「状态定义-初始化-状态转移-结果追踪」的动态规划四步走。需要重点注意遍历顺序(按子串长度从小到大)和边界条件处理(字符串长度<2、右边界越界)。

M18277的博客 476

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【每日算法】LeetCode 5. 最长回文子串(动态规划)

前端开发者学习算法有助于从"页面构建者"进阶为"复杂系统设计者",提升问题解决能力。LeetCode第5题"最长回文子串"考察字符串处理能力,其最优解为中心扩散法,时间复杂度O(n²),空间复杂度O(1)。该算法利用回文串的对称性,遍历每个可能的中心并向两侧扩展,比动态规划法更节省空间。掌握此类算法能提升前端开发中字符串处理、性能优化等核心技能,是技术进阶的关键。

LYFlied的博客 1043

力扣算法题:字符串(最长公共前缀|最长回文子串)

本文介绍了两种字符串算法:1.最长公共前缀问题,提出两种解法:两两比较法(逐个字符串比较)和统一比较法(以首个字符串为基准);2.最长回文子串问题,采用中心扩展算法,分别处理奇数和偶数长度的回文情况。两种算法均通过边界条件处理和字符逐一比较实现,代码展示了具体实现过程。

分享C,C++,数据结构,Linux,算法内容 304

最长回文子串 Java 题解,中心扩展法详解

奇数长度回文:只有一个中心字符,例如aba的中心是b;偶数长度回文:中心位于两个字符之间,例如abba的中心是bb之间的间隙。因此,遍历字符串时,每个位置都要尝试两种中心。每个字符尝试一次奇数中心;每个字符间隙尝试一次偶数中心;左右字符相等就继续扩展;记录遇到的最长区间并返回。这套方法时间复杂度为O(n²)、空间复杂度为O(1),实现简单且不容易出错。需要进一步优化到O(n)时,再学习 Manacher 算法即可。更多技术实践与案例,可在 📗【姚前述】中查阅。

ydd100100的博客 301

【LeetCode】5-最长回文子串

欢迎来到李耶的频道【LeetCode面试题】。

李耶的随文笔记 163

两道必掌握的动态规划面试题:最长回文子串 & 最长公共子序列

本文介绍了算法面试中两道经典动态规划问题:最长回文子串和最长公共子序列。最长回文子串可采用中心扩展法(O(n²)时间)或动态规划(O(n²)空间),核心在于利用回文串的对称性。最长公共子序列推荐使用二维动态规划(O(mn)时间),通过状态转移方程记录子问题解,并可优化空间至O(min(m,n))。两道题的区别在于:前者处理连续子串,后者处理非连续子序列。掌握这两道题有助于建立动态规划解题思维,是算法面试的重要基础。

2401_84526799的博客 454

LeetCode 5 最长回文子串

本文介绍了寻找字符串中最长回文子串的算法。采用中心扩展法,通过遍历字符串中的每个字符作为回文中心,分别处理奇数和偶数长度的回文情况。算法时间复杂度为O(n²),空间复杂度为O(1)。Java、C++和Python实现均包含核心逻辑:expandAroundCenter函数负责中心扩展,主函数负责遍历并更新最长回文记录。该算法能高效处理最长回文子串问题,适用于长度不超过1000的字符串。

qq_44652502的博客 47

【leetcode】5.最长回文子串js

本文介绍了两种解决最长回文子串问题的算法。中心扩散法通过遍历字符串,以每个字符为中心向两边扩散寻找回文,分别处理奇数和偶数长度的情况。动态规划法则定义dp[i][j]表示子串s[i...j]是否为回文,通过状态转移规则和初始化条件求解,最终记录最长回文的起始位置和长度。两种方法各有特点,中心扩散法直观易理解,动态规划法则展现了更系统的解题思路。文中提供了完整的JavaScript实现代码,适合算法学习者参考。

2402_83244812的博客 239

LeetCode 005. 最长回文子串 - 中心扩展、动态规划与 Manacher 详解

题目描述:给定一个字符串 s,返回 s 中最长的回文子串。如果存在多个长度相同的答案,返回任意一个即可。原题链接:https://leetcode.cn/problems/longest-palindromic-substring/难度等级:Medium相关标签:字符串、双指针、动态规划、Manacher| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 | 适用场景 |

m0_52114506的博客 510

LeetCode hot100 【多维动态规划】最长回文子串(各种解法层层递进 )

本文分析了最长回文子串问题的多种解法:暴力解法时间复杂度O(n³);DFS+备忘录优化为O(n²);动态规划自底向上解法;中心扩展法(面试推荐,O(n²));以及Manacher算法(唯一线性O(n)解法)。重点比较了不同方法的时间复杂度和适用场景,其中中心扩展法实现简单效率较高,而Manacher算法最优但实现复杂。每种解法都附有对应力扣题目链接供参考。

weixin_45839019的博客 57

leetcode 第5题 最长回文子串(动态规划解法)

leetcode 第五题 最长回文子串 的 动态规划解法 是一个经典的 动态规划 解决中等题型的 入门指导。因为 这里用到了状态转移方程的 二维数组形式 dp[][]

luolvzhou的博客 322
上一篇: 动态规划—输出所有的最长公共子序列
下一篇: 出栈序列统计—中学高级本
tham_
博客等级 码龄12年 233粉丝 105原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值