给你一个字符串 s,找到 s 中最长的回文子串。
示例1
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例2
输入:s = "cbbd"
输出:"bb"
示例2
输入:s = "ccc"
输出:"ccc"
解决的思路:
1 先判定特殊情况,如字符串的中只有1个元素或者为空时;
2 确定出中间相同的部分,比如‘cbbd‘中的bb
3 确定出相同部分元素两边共同的元素,比如“afsssf”中的fsssf
4 比较找出的回文子串的长度,返回最长的回文子串
具体做法已备注如下:
用whiles实现
class Solution:
def longestPalindrome(self, s: str) -> str:
# 长度为小于等于1的话直接返回字符串
if len(s) <= 1:
return s
tup = [0, 0] #
for i in range(len(s)):
left = i
right = i
# 更新相同部分元素最左边元素位置的索引
while left >=0 and s[i] == s[left]:
left -= 1
# 更新相同部分元素最右边元素位置的索引
while right <= len(s) -1 and s[i] == s[right]:
right += 1
# 找完相同部分的元素后找两边是否还有相同的元素,更新索引
while left >= 0 and right <= len(s) -1 and s[left] == s[right]:
left -=1
right +=1
# 比较并更新回文子串最左和左右两边的元素的索引,找出最长的
if right - left > tup[1]-tup[0]:
tup[0],tup[1] = left,right
return s[tup[0]+1:tup[1]]
for循环实现
class Solution:
def longestPalindrome(self, s: str) -> str:
# 长度为小于等于1的话直接返回字符串
if len(s) <= 1:
return s
tup = [0, 0]
for i in range(len(s)):
left = i
right = i
# 找出相同元素左边一个元素的索引
for j in range(0, i + 1):
if s[left] == s[left - j]:
# 如果全部元素相同,即从索引0到索引len(s)-1位置上的元素都相同 返回-1
if j==i:
left = -1
continue
else:
# 如果遍历的j个元素相同,返回全部相同元素的左边一个的索引
left = left - j
break
# 找出相同元素的最右边过去一个位置的索引
for j in range(i, len(s)):
if s[right] == s[j]:
# 如果字符串元素都相同,返回索引为len(s),便于统一和不是所有元素相同时计算
if j == len(s)-1:
right = len(s)
continue
else:
right = j
break
# 定义tmp接收左右两边到相同部分元素的距离
tmp = 0
# 因为有可能left=-1 right=len(s)的时候,所以先要圈定范围;再判断那边元素更少,遍历元素更少的一侧
if left >=0 and right <= len(s)-1 and len(s)- right <= left+1:
# 当右边剩下的元素比较少时
for j in range(len(s) - right):
# 如果存在相同的元素,需要注意的地方是比如aba这种,当i=1遍历完就结束了,得返回一个距离才行
if s[left - j] == s[right + j]:
if j == len(s)-right-1:
# 当遍历完后后,即j为遍历的最后一个元素,距离应该tmp不然无法接收aba左右两边的a
tmp = j+1
continue
else:
tmp = j
break
# 与上一个if对应,但是都要满足边界的条件,元素长度进行选择判断
elif left >=0 and right <= len(s)-1:
for j in range(left + 1):
if s[left - j] == s[right + j]:
if j== left:
tmp = j+1
continue
else:
tmp = j
break
# 比较回文串的长度,并更新留下更长的字符串的索引;长度用距离表示,right-tmp-(left-tmp)左边减右边
if right - left + 2 * tmp > tup[1] - tup[0]:
tup[0], tup[1] = left - tmp, right + tmp
#返回回文串 切片区间左闭右开,tup[0]是最左边不相同的元素即afgggd中的f,因为左闭右开所以要+1
return s[tup[0]+1:tup[1]]
总结:
1)对我来说第一步没有明确left和right索引如何更新和更新的条件是个不熟悉的地方,whlie循环比for循环貌似对这题简易一些。
1.while循环只需要明确可以更新的条件(索引的范围和元素相等时的情况);for循环首先要考虑范围,左边的是(0,i+1),右边是(i,len(s)-1);
2.其次是更新的方法,left由于是往左边走,所以更新时是left-j(j为迭代变量),right的话,由于范围是从i开始了,所以并不是直接加上迭代变量,而应该是等于迭代变量j。
3.还有一个坑是在遇到所有元素都相同的情况下,比如“ccc”,如果持续continue(因为走不到else上),会导致left=right=2,为了避免,需要在contunie结束前进行判断和接收left、right的值。当左边遍历完到位置0时元素都相同时,应该接收left为-1.右边同理。
2)在寻找除了中间部分相同元素之外的是否有左右两边相同元素的情况时,出现过aba只找出b,没有返回出旁边的两个a的错误。这个错误类似“ccc”这种left和right的情况,所以需要在continue前接收tmp, 添加判断条件在遍历到最边上时,让tmp+1,
3)if 和只有一个elif在配套使用时,如果两个条件都需要满足那都需要写上,差异的可以不写
保持期待,奔赴山海