python最长回文子串leetcode_LeetCode 最长回文子字符串

求一个字符串的最长回文子字符串,网上分析的文章不计其数

虽然昨天用C完成了一份,但感觉C写这类代码真是不方便,还是java或者python比较好,改天放一个python的版本上来

对于网上的代码,补充一点分析,主要是对于开始几步。先看一下LeetCode的代码:// Transform S into T.

// For example, S = "abba", T = "^#a#b#b#a#$".

// ^ and $ signs are sentinels appended to each end to avoid bounds checking

string preProcess(string s) {

int n = s.length();

if (n == 0) return "^$";

string ret = "^";

for (int i = 0; i 

ret += "#" + s.substr(i, 1);

ret += "#$";

return ret;

}

string longestPalindrome(string s) {

string T = preProcess(s);

int n = T.length();

int *P = new int[n];

int C = 0, R = 0;

for (int i = 1; i 

int i_mirror = 2*C-i; // equals to i' = C - (i-C)

P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;

// Attempt to expand palindrome centered at i

while (T[i + 1 + P[i]] == T[i - 1 - P[i]])

P[i]++;

// If palindrome centered at i expand past R,

// adjust center based on expanded palindrome.

if (i + P[i] > R) {

C = i;

R = i + P[i];

}

}

// Find the maximum element in P.

int maxLen = 0;

int centerIndex = 0;

for (int i = 1; i 

if (P[i] > maxLen) {

maxLen = P[i];

centerIndex = i;

}

}

delete[] P;

return s.substr((centerIndex - 1 - maxLen)/2, maxLen);

}

其中,以下这段代码比较好理解,可结合各种文章的分析while (T[i + 1 + P[i]] == T[i - 1 - P[i]])

P[i]++;

// If palindrome centered at i expand past R,

// adjust center based on expanded palindrome.

if (i + P[i] > R) {

C = i;

R = i + P[i];

}

但是比较难理解的是初始化条件和初始的判断语句int C = 0, R = 0;

for (int i = 1; i 

int i_mirror = 2*C-i; // equals to i' = C - (i-C)

P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;

按照辅助字符串构造方法,开始时C和R位于串首'^'处,i位于第一个'#'处,i_mirror位于-1处

此时算法从第一个'#'处记录各个位置的最长回文子串的半径,其实完全可以从P[2]处也即第一个实际字符处开始记录,但这样边界条件的处理会稍微复杂一点。

记住,R代表了目前所找到的回文子串的最右边界,对于每一个原文字符串,P[i]至少为1因为两边有'#',而对每一个'#',可能为0.

所以对于i如果等于或者大于R,P[i]肯定是要重新计算了,所以要置0,而如果i没有超过R,则说明i还在当前所有回文子串的最右边界范围内,或者说T[i]位置的字符是被某一个回文子串包含了,而这个字符串的中心就是C。注意,C并不等于i,例如图中C等于11,但i等于15,C为中心的子串半径很大

此时P[i]的值可以参考它的对称点的值,如果对称点为中心的回文子串完全落在C为中心的回文子串范围内,则很显然P[i]=P[i_mirror],如果不是的话,就只能确保i为中心,R为右边界的子串为回文,至于再往两边是不是则需要程序判断了,,所以此时需要设P[i]=R-i,而判断i_mirror为中心的子串是否完全落在C为中心的回文子串范围内,就是比较R-i和P[i_mirror]的大小,实际上R-i等价于i_mirror-L

再回到开始吧,R什么时候大于i?就是找到了某个半径大于1的子串之后而i还没有突破R的边界

R什么时候会小于i?当走到右边界之后还没有找到更新的回文子串,也就是某次循环的末尾i=R,P[i]=0

当下次循环开始的时候,i=R+1,所以此时P[i]=0。

可以看出,初始化时就是i=R+1的情况,所以初始循环条件成立。

补充一下,LeetCode的源码有问题,有人看出来了吗?

说一下吧,如果原文字符串即以'^'开头,而且后面没有回文子串了,那么P[i]=1就是找到的maxLen!

此时取子串时  (centerIndex - 1 - maxLen)/2 被除数会出现负数,虽然不影响具体结果(输出第一个字符),但多多少少算不严谨吧。

解决方法,找P[i]最大值时从i=2开始找即可,因为这才是实际的第一个字符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,有三种方法可以解决LeetCode上的最长回文子串问题。 方法一是使用扩展中心法优化,即从左向右遍历字符串,找到连续相同字符组成的串作为扩展中心,然后从该中心向左右扩展,找到最长回文串。这个方法的时间复杂度为O(n²)。\[1\] 方法二是直接循环字符串,判断串是否是回文串,然后得到最长回文子串。这个方法的时间复杂度为O(n³),效率较低。\[2\] 方法三是双层for循环遍历所有串可能,然后再对比是否反向和正向是一样的。这个方法的时间复杂度也为O(n³),效率较低。\[3\] 综上所述,方法一是解决LeetCode最长回文子串问题的最优解法。 #### 引用[.reference_title] - *1* [LeetCode_5_最长回文子串](https://blog.csdn.net/qq_38975553/article/details/109222153)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode-最长回文子串](https://blog.csdn.net/duffon_ze/article/details/86691293)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LeetCode 第5题:最长回文子串Python3解法)](https://blog.csdn.net/weixin_43490422/article/details/126479629)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值