求一个字符串中最长回文子串的长度(承接上一个题目)

问题描述:如题,给定一个字符串str和其长度n,求该字符串的一个最长公共回文子串的长度(公共子串个公共子序列是两个不同的概念)。并打印出该回文子串。
解答:1,首先给出一个比较直观的解法。根据回文的性质,我们可以把str进行逆转得到str1,然后求str和str1的最长公共子串,那么该子串的长度就是str的最长回文子串的长度,该公共子串就是最长的那个回文子串。也即我们把这个题目转化为求两个字符串str和str1的最长公共子串的问题。我们假设C[i,j]为以str[i]和str1[j]结尾的最长公共子串的长度,那么状态转移方程为:
C[i,j]=0 if(str[i]!=str1[j])
C[i,j]=c[i-1,j-1]+1  if(str[i]==str1[j])
初始条件为C[0,0]=0;最初的时间代价为O(n^2),空间代价为O(n^2),空间代价还可以优化为O(n),只需要j的循环式从高往低即可。代码如下:
//求str1和str2的最长公共子串,下标从1算起
void LCS_continue(char *str1,int n1,char *str2,int n2){
int **C=new int*[n1+1];
for(int i=0;i<=n1;i++){
C[i]=new int[n2+1]();
}
int max=0;
int max_index_i=0;
int max_index_j=0;
for(int i=1;i<=n1;i++){
for(int j=1;j<=n2;j++){
if(str1[i]==str2[j])
C[i][j]=C[i-1][j-1]+1;
else
C[i][j]=0;
if(C[i][j]>max){
max=C[i][j];
max_index_i=i;
max_index_j=j;
}
}
}
cout<<"最长公共子串长度为:"<<max<<ends;
if(max>0){
cout<<"子串为:"<<ends;
while(str1[max_index_i]==str2[max_index_j--]){
cout<<str1[max_index_i--]<<ends;
}
}
//free mem
for(int i=0;i<=n1;i++){
delete [] C[i];
}
delete [] C;
}
空间优化:
void LCS_continue_OPM(char *str1,int n1,char *str2,int n2){
int *C=new int[n2+1]();
int max=0;
int max_index_j=0;
for(int i=1;i<=n1;i++){
for(int j=n2;j>0;j--){
if(str1[i]==str2[j])
C[j]=C[j-1]+1;
else
C[j]=0;
if(C[j]>max){
max=C[j];
max_index_j=j;
}
}
}
cout<<"最长公共子串长度为:"<<max<<ends;
if(max>0){
cout<<"子串为:"<<ends;
while(max>0){
cout<<str2[max_index_j--]<<ends;
max--;
}
}
//free mem
delete [] C;
}
2,下面给出一个直观的动规解,

转载于:https://www.cnblogs.com/kevinLee-xjtu/archive/2011/12/21/2299082.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 回文子串是指正着读和倒着读都一样的字符串。要找出一个字符串最长回文子串。 解决这个问题的方法有很多,其一种比较简单的方法是暴力枚举。具体来说,我们可以枚举所有可能的子串,然后判断每个子串是否是回文串,最后找出最长回文子串。 具体实现时,我们可以从字符串的第一个字符开始,依次枚举所有可能的子串。对于每个子串,我们可以使用双指针法来判断它是否是回文串。具体来说,我们可以使用两个指针分别指向子串的首尾字符,然后依次向间移动,判断对应的字符是否相等。如果所有字符都相等,那么这个子串就是回文串。 在判断完所有子串之后,我们就可以找出最长回文子串了。具体来说,我们可以用一个变量来记录当前找到的最长回文子串长度,以及它的起始位置。在枚举所有子串的过程,如果找到了一个更长的回文子串,那么就更新这个变量。 需要注意的是,由于字符串可能存在偶数长度回文子串,因此我们需要分别枚举以每个字符为心的奇数长度回文子串和以每两个相邻字符为心的偶数长度回文子串。 这种暴力枚举的方法时间复杂度为O(n^3),其n是字符串长度。虽然时间复杂度比较高,但是这种方法比较简单易懂,可以作为其他更高效的算法的基础。 ### 回答2: 回文子串是指正着读和倒着读一样的字符串。例如,'level'和'noon'就是回文子串。编写程序来寻找给定字符串最长回文子串。 一种常见的方法是暴力枚举字符串的所有子串并检查它们是否是回文。这种方法的时间复杂度为O(n^3),不适用于长字符串。另一种常见的方法是动态规划。这种方法的时间复杂度为O(n^2),适用于较长的字符串。 动态规划方法的主要思路如下: 1.定义状态:dp[i][j]表示从i到j的子串是否为回文。 2.初始化状态:对于所有i,dp[i][i]都是true。 3.状态转移:当s[i] = s[j]时,如果dp[i+1][j-1]是true,那么dp[i][j]也是true。 4.记录最长回文子串的起始位置和长度:遍历dp数组,找到值为true且长度最大的子串即可。 下面是一个Python实现的例子: ```python def longest_palindrome(s:str) -> str: if not s: # 处理输入为空的情况 return "" n = len(s) dp = [[False] * n for _ in range(n)] # 初始化dp数组 start, max_len = 0, 1 # 记录最长回文子串的起始位置和长度 for i in range(n): # 初始化对角线上的状态 dp[i][i] = True for j in range(1, n): for i in range(0, j): if s[i] == s[j]: if j - i < 3: # 特判长度小于3的情况 dp[i][j] = True else: dp[i][j] = dp[i+1][j-1] else: dp[i][j] = False if dp[i][j]: # 记录最长回文子串的起始位置和长度 if j - i + 1 > max_len: max_len = j - i + 1 start = i return s[start:start+max_len] ``` 该算法的时间复杂度为O(n^2),空间复杂度也为O(n^2)。 ### 回答3: 回文串指正着读和倒着读都一样的字符串,例如 "level", "noon" 等。在一个字符串,可能不存在回文子串,也可能存在多个长度相同的回文子串。现在给定一个字符串,需要我们出其最长回文子串。 解决此问题,可以用动态规划算法。假设字符串长度为 n,定义一个二维数组 dp (n * n),其 dp[i][j] 表示从 i 到 j 这一段字符串是否为回文串。当字符串为空或长度为 1 时,皆为回文串(即 dp[i][i] = true)。当字符串长度大于等于 2 时,若第 i 个字符和第 j 个字符相等,且从 i + 1 到 j - 1 的字符串也是回文串,那么从 i 到 j 的字符串也是回文串(即 dp[i][j] = dp[i + 1][j - 1] && s[i] == s[j])。此外,记录回文子串的起始位置和长度,最终找到最长回文子串即可。 以下是 Python 代码实现: ``` class Solution: def longestPalindrome(self, s: str) -> str: n = len(s) dp = [[False] * n for _ in range(n)] res = "" for i in range(n - 1, -1, -1): for j in range(i, n): dp[i][j] = s[i] == s[j] and (j - i < 3 or dp[i + 1][j - 1]) if dp[i][j] and j - i + 1 > len(res): res = s[i:j+1] return res ``` 时间复杂度为 O(n^2),空间复杂度为 O(n^2)。总的来说,动态规划算法是解决最长回文子串问题的一种行之有效的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值