本文已参与「新人创作礼」活动,一起开启掘金创作之路
题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 示例 2:
输入:s = "cbbd" 输出:"bb" 示例 3:
输入:s = "a" 输出:"a" 示例 4:
输入:s = "ac" 输出:"a"
提示:
1 <= s.length <= 1000 s 仅由数字和英文字母(大写和/或小写)组成
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/lo… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析
很显然暴力遍历是一种方法 比如说:
L = (input())
count = 0
len1 = len(L)
for i in range(len1):
for each in range(i, len1):
if L[i:each] == L[each:i:-1]:
len2 = len(L[i:each])
if len2 > count:
s = L[i:each+1]
count = len2
print(s)
但这样一般情况下会超时 所以我们换另一种比较好理解的思路,由子串的中心向两边展开,也就是模拟双指针。 首先我们要找最长回文子串的特点: 我们会发现回文子串都可以分成这两种 1. 长度为偶数就是两两相等,如:abba 2. 长度为奇数就是中心除外两两相等, 如:abcba 3. 无论是aaaa或者aaaaa也可以归到这两类中 知道这几点后就可以实现代码了
代码实现
s = input()
def longestPalindrome(s):
# 因为下面的代码对 len(s) <= 2时非回文子串无法判定(如:a 或 ac),所以先让 result 等于第一个字符, 这样回文子串的长度为 1
result = s[0]
len_res = 1
# 第一种情况: aba 或 aaa
for i in range(1, len(s)):
start = i - 1
end = i + 1
while True:
if start > 0 and end < len(s) - 1 and s[start] == s[end]:
start -= 1
end += 1
else:
break
if start >= 0 and end <= len(s) - 1:
if s[start] == s[end]:
if end - start + 1 > len_res:
len_res = end - start + 1
result = s[start: end+1]
else:
# 这里 start += 1 和 end -= 1 是因为满足 start > 0 and end < len(s) - 1 and s[start] == s[end] 时 start -= 1, end += 1。然后我们需要判定边界是否相等, 即:s[start] == s[end],如果不相等,那就退一步,即: start += 1 和 end -= 1
start += 1
end -= 1
# 判断遍历的回文子串是不是最长的
if end - start + 1 > len_res:
len_res = end - start + 1
result = s[start: end+1]
# 第二种情况:abba 或 aaaa
for i in range(0, len(s)):
start = i
end = i+1
while True:
if start > 0 and end < len(s) - 1 and s[start] == s[end]:
start -= 1
end += 1
else:
break
if start >= 0 and end <= len(s) - 1:
if s[start] == s[end]:
if end - start + 1 > len_res:
len_res = end - start + 1
result = s[start: end+1]
else:
start += 1
end -= 1
if end - start + 1 > len_res:
len_res = end - start + 1
result = s[start: end+1]
return result
print(longestPalindrome(s))
代码优化
我们会发现两种不同的类型的回文子串的查找方式很像,所以我们可以把这些代码模块化,即自定义函数 (这好像是力扣的官方解法)
L = input()
def expendAroundCenter(s, left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return left + 1, right - 1
'''
因为满足 left >= 0 and right < len(s) and s[left] == s[right] 后 left -= 1, right += 1
但又因为退出循环 所以 满足回文的是 left + 1 和 right - 1
'''
def longestPalindrome(s):
start, end = 0, 0
for i in range(len(s)):
'''
若回文子串为奇数,则中间的字只出现一次,如“aba”。
所以从中间查找,只有 s[i]==s[i]
'''
left1, right1 = expendAroundCenter(s, i, i)
if right1 - left1 > end - start:
start, end = left1, right1
'''
若回文子串为偶数,则字出现两次,如“abba”。
所以从中间查找,有 s[i]==s[i+1]
'''
left2, right2 = expendAroundCenter(s, i, i + 1)
if right2 - left2 > end - start:
start, end = left2, right2
return s[start : end + 1]
print(longestPalindrome(L))