数组和字符串
KMP(串的模式匹配):
- 每一个字符前的字符串都有最长相等前后缀,而且最长相等前后缀的长度是我们移位的关键,所以我们单独用一个next数组存储子串的最长相等前后缀的长度。而且next数组的数值只与子串本身有关。
-

- next数组作用
- next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度。
- 表示该处字符不匹配时应该回溯到的字符的下标
- 事实上现在的算法已经不用next了,都是使用标准的前缀函数。它们的关系是把前缀函数整体右移一位,并在开头补
-1或0,就是前缀函数。 -
def get_pre(s:str)->list: if not s: return [] i=0 pre=[0]*len(s) for j in range(1,len(s)): while i>0 and s[j]!=s[i]: i=pre[i-1] if s[j]==s[i]: i+=1 pre[j]=i return nxt前缀函数告诉你已经匹配了多少个字符。
-
搜索:
-
def kmp_search(text, pattern): if not pattern: return [] # 空模式串,按需处理 n = len(text) m = len(pattern) # 1. 计算模式串的前缀函数 pi = compute_prefix_function(pattern) matches = [] # 存储所有匹配的起始索引 j = 0 # 模式串当前匹配的长度(即 pattern[0:j] 已匹配) for i in range(n): # 遍历主串 # 当前字符不匹配时,利用前缀函数回退 j while j > 0 and text[i] != pattern[j]: j = pi[j - 1] # 回退到 pi[j-1] 的位置继续匹配 # 如果字符匹配,扩展匹配长度 if text[i] == pattern[j]: j += 1 # 如果整个模式串都匹配了 if j == m: start_index = i - m + 1 # 匹配的起始位置 matches.append(start_index) # 可选:继续查找下一个匹配 j = pi[j - 1] # 利用前缀函数跳转,避免重复匹配 return matches
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
i=0
pre=[0]*len(needle)
for j in range(1,len(needle)):
while i>0 and needle[j]!=needle[i]:
i=pre[i-1]
if needle[j]==needle[i]:
i+=1
pre[j]=i
i=0
for j in range(len(haystack)):
while i>0 and haystack[j]!=needle[i]:
i=pre[i-1]
if haystack[j]==needle[i]:
i+=1
if i==len(needle):
return j-len(needle)+1
return -1
双指针
双指针的典型场景之一是你想要从两端向中间迭代数组。
还有一种情况是同时有一个慢指针和一个快指针。解决这类问题的关键是:确定两个指针的移动策略。
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
前缀和 + 二分查找
用 >> 1 是一种位运算优化技巧,在底层比除法 // 2更快
官方解法如下:
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
if not nums:
return -1
sums=[0]
presum=0
for num in nums:
presum+=num
sums.append(presum)
ans=len(nums)+1
for i in range(len(nums)):
s=target+sums[i]
j=bisect_left(sums,s)
# 返回sums数组中第一个>=s的索引
if j!=len(sums):
ans=min(j-i,ans)
return 0 if ans==len(nums)+1 else ans
滑动窗口
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
if not nums:
return 0
start,end=0,-1
total=0
ans=len(nums)+1
while end <len(nums)-1:
end += 1
total += nums[end]
while total >= target:
ans = min(ans, end - start + 1)
total -= nums[start]
start += 1
return 0 if ans == len(nums) + 1 else ans
class Solution:
def findMin(self, nums: List[int]) -> int:
l,r=0,len(nums)-1
while l<r:
mid=(l+r)//2
if nums[mid]>nums[r]:
l=mid+1
else:
r=mid
return nums[l]
原来这书只有第一本是免费的 哈哈哈哈哈 溜了
531

被折叠的 条评论
为什么被折叠?



