力扣第5题:马拉车算法

力扣第五题:寻找最长回文串

这个题的难点在于:
① 回文串中的字符可能有奇数个,也有可能有偶数个。若用一般方法,必须得分奇偶讨论。
eg: a b c d c b a
上述最长回文字符串为奇数个,对称轴为 d
a b b a
上述最长回文串为偶数个,对称轴为 b b

而只要将字符串做如下调整:
#a#b#c#d#a#b#c#
#a#b#b#a#
最长字符串的个数就成了奇数个,不需要分类讨论。

② 对字符串从左到右,以每一个字符为中心轴进行左右扩展,每一次扩展的起始半径都为1,造成了不必要的重复,时间复杂度较高。

解决办法:马拉车算法
优点:若是一般方法的左右拓展,RL的值必须从1开始拓展,但马拉车算法高效得求得了RL[i]数组,降低了时间复杂度。

RL[i]为以 i为轴扩展的回文串的半径
Maxright 为所能触及的回文串的最右
pos为所能触及最长回文串的对称轴

在解决这道题之前,我们首先要知道已经变成奇数个的字符串s1中,RL[i]-1 为以 I 为中心的回文串的长度。那么问题就变成了如何高效的求 RL[i] 数组

在从左往右遍历 i 的过程中,要考虑 i 与 Maxright 的相对位置:
(1)i 在 Maxright 的左边,i 关于pos的对称位置为 j 。

第一种情况,j 很短,没有超过 Maxright 关于pos的对称位置,那么RL[i]就以RL[j] 为初始半径开始左右扩展,而RL[j]在遍历到 i 之前已经求过,所以RL[i]=RL[2*pos-1];

第二种情况,j很长,已经超过了Maxright关于pos的对称位置,我们所能看到的 RL[i] 的仅仅是 Maxright-i 的部分,所以RL[i] 以Maxright-1 为起始半径开始左右扩展。

(2)i 在Maxright的右边,说明 i 所在的位置还未触及,RL[i]的初始值为1。

if(i<MaxRight)      
    RL[i]=min(RL[2*pos-i],MaxRight-i);       
else      
   RL[i]=1;

当超过左边界、超过有边界或者两边的字符不相等时,扩展结束。

while(i>=RL[i]&&i+RL[i]<len&&s1[i-RL[i]]==s1[i+RL[i]])
RL[i]+=1;

实时更新 MaxRight 和 pos 的值。
最后更新 Maxpos 和MaxRL的值。

class Solution {
public:
    string longestPalindrome(string s) {
                int len=s.length();
                if(len<1)
                return "";
                string s1;            
                for(int i=0;i<len;i++)            
                {            
                 s1+="#";            
                 s1+=s[i];                
                 }            
                 s1+="#";//使成为奇数j字符串            
                 len=s1.length();            
                 int MaxRight=0;            
                 int pos=0;            
                 int MaxPos=0;            
                 int MaxRL=0;            
                 int *RL=new int [len];            
                 memset(RL,0,len*sizeof(int));//初始化	RL数组            
                 for( int i=0;i<len;i++)            
                 {                
                 if(i<MaxRight)                
                 RL[i]=min(RL[2*pos-i],MaxRight-i);                
                 else                
                 RL[i]=1;                
                 while(i>=RL[i]&&i+RL[i]<len&&s1[i-RL[i]]==s1[i+RL[i]])               
                 RL[i]+=1;                                  
                 if(i+RL[i]-1>MaxRight)            
                 {               
                    MaxRight=i+RL[i]-1;                
                    pos=i;                           
                 }           
                 if(RL[i]>=MaxRL)           
                 {
                     MaxRL=RL[i];                
                     MaxPos=i;            
                 }     
                 }
                                                     
 return s.substr((MaxPos-MaxRL+1)/2,MaxRL-1);/MaxPos-MaxRL+1)/2为最长回文串的起始位置,MaxRL-1为最长回文串的长度   
 }      
 };
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
目描述: 给你两个版本号 version1 和 version2 ,请你比较它们。 版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从0开始,最左边的修订号下标为0 ,下一个修订号下标为1,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。 比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。也就是说,修订号1和修订号001相等。如果版本号没有指定某个下标处的修订号,则该修订号视为0。例如,版本1.0 小于版本1.1,因为它们下标为0的修订号相同,而下标为1的修订号分别为0和1,0 < 1。 返回规则如下: 如果 version1 > version2 返回 1, 如果 version1 < version2 返回 -1, 否则返回 0。 示例 1: 输入:version1 = "1.01", version2 = "1.001" 输出:0 解释:忽略前导零,"01" 和 "001" 都表示相同的整数 "1" 示例 2: 输入:version1 = "1.0", version2 = "1.0.0" 输出:0 解释:version1 没有指定下标为 2 的修订号,即视为 "0" 示例 3: 输入:version1 = "0.1", version2 = "1.1" 输出:-1 解释:version1 中下标为 0 的修订号是 0,version2 中下标为 0 的修订号是 1 。0 < 1,所以 version1 < version2 示例 4: 输入:version1 = "1.0.1", version2 = "1" 输出:1 示例 5: 输入:version1 = "7.5.2.4", version2 = "7.5.3" 输出:-1 提示: 1 <= version1.length, version2.length <= 500 version1 和 version2 仅包含数字和 '.' version1 和 version2 都是 有效版本号

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值