> 最常见的就是本办法不断的循环获取各个区间,在不同的区间进行判断
> 采用双指针+字典的方式进行位置保存,跳过无效位置的无效判断,本质上双指针就是确定有效区间的起点和终点。
第一种方法:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
def getqu(i, j):
return s[i:j+1]
def just(cur):
dic = {}
for i in cur:
if i not in dic:
dic[i] = 1
else:
return False
return True
max_ = 0
for i in range(len(s)):
for j in range(len(s)):
if just(getqu(i, j)):
max_ = max(max_, j-i+1)
return max_
第二种方法:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
max_ = 0
dic = {}
start = 0
index = 0
while index < len(s):
cur = s[index]
if cur in dic:
# 新字符重复后,有效长度是当前重复字符前一个位置到上次重复字符的后一个位置
# 其实就是确定不重复字段的起点终点,
# 所以结果是index-1 - start + 1 = index - start
max_ = max(max_, index - start)
start = max(start, dic[cur] + 1) # 注意start有可能回缩
dic[cur] = index
index += 1
return max(max_, index - start) # 考虑到最后字符不再dic中,会造成长度增加
2.最长回文子串
其实本质上就是三种做法:官方写法:官方解读
第一是时间复杂度是O(n^2),空间复杂度也是O(n^2),这里使用的动态规划的思想 熟悉动态规划
第二是时间复杂度是O(n^2),空间复杂度是O(1),这里使用的是最直接的想法,就是找中点,左右两侧扩展
第三是相对比较复杂的Manacher算法,具体可以查看力扣的解读。 熟悉空间换时间 熟悉利用前面的思想 还是动态规划
解析链接:下面三句话至关重要,要仔细理解
方法一:本质上是设置二维数组,然后动态规划的方程就是p(i+1,j-1) = True and s[i] == s[j],这个
这就是回文串,默认至少2个字符,所以初始化二维数组需要先将二个字符的初始化了(即初始化对角线以及对角线的右上线),这句话既是初始化数组方法,也是暗含了对于奇数和偶数回文串的两种情况,主对角线是奇数,次主对角线是偶数。
从执行过程分析是按照斜对角的方式由右下到左上不断的迭代,直到迭代到右上角。
从本质上分析其实就是枚举罗列的办法,也会dp类方法有更加深刻的认识。
class Solution:
# 动态规划使用python会超时 也不是换种更加简便的方法就不超时了
def longestPalindrome(self, s: str) -> str:
if not s:
return None
if len(s) == 1:
return s
# 定义返回函数
def getCur(i, j, cur):
if j-i+1 > len(cur):
return s[i:j+1]
return cur
# 初始化主对角线
cur = s[0]
dp = [[True if i == j else False for i in range(len(s))] for j in range(len(s))]
# 初始化右斜对角线
for i in range(len(s)-2, -1, -1):
j = i+1
if s[i] == s[j]:
dp[i][j] = True
cur = getCur(i, j, cur)
else:
dp[i][j] = False
# 开始迭代
for line in range(len(s)-3, -1, -1):
for i in range(line, -1, -1):
j = i+(len(s)-line-1)
if s[i] == s[j] and dp[i+1][j-1]:
dp[i][j] = True
cur = getCur(i, j, cur)
else:
dp[i][j] = False
return cur
方法二:中心扩散法 考试的话可以说动态规划的思路,但是写的话还是写这种方法吧,空间复杂度是1
class Solution:
def longestPalindrome(self, s: str) -> str:
if (not s or len(s) == 1):
return s
cur = s[0]
for i in range(len(s)):
def adjustQ(i, cur):
left = i - 1
right = i + 1
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
left += 1
right -= 1
return s[left:right + 1] if right - left + 1 > len(cur) else cur
def adjustO(i, cur):
p = i + 1
if p >= len(s) or s[i] != s[p]:
return cur
left = i - 1
right = i + 2
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
left += 1
right -= 1
return s[left:right + 1] if right - left + 1 > len(cur) else cur
cur = adjustQ(i, cur)
cur = adjustO(i, cur)
return cur
方法三:https://ethsonliu.com/2018/04/manacher.html 这个链接分析的还可以
class Solution:
def longestPalindrome(self, s: str) -> str:
if (not s or len(s) == 1):
return s
s = '#' + '#'.join(list(s)) + '#'
maxRight = 0
center = 0
iToLenth = [0]
cur = s[0]
indexMax = 0
maxLenth = iToLenth[indexMax]
for i, charCur in enumerate(s[1:], 1):
if i > maxRight: # 运动到了右界之后,需要新的中心扩展
iToLenth.append(0)
left = i - 1
right = i + 1
else: # 在右界内部,获取点关于对称点的对称值,切记下面的公式
iToLenth.append(min(iToLenth[2 * center - i], maxRight-i))
left = i - (iToLenth[i] + 1)
right = i + (iToLenth[i] + 1)
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
iToLenth[i] += 1
if iToLenth[i] + i > maxRight:
maxRight = i + iToLenth[i]
center = i
if iToLenth[i] > maxLenth:
maxLenth = iToLenth[i]
indexMax = i
return s[indexMax-maxLenth+1:indexMax+maxLenth+1:2]