力扣学习 力扣官方电子学习书

数组和字符串

KMP(串的模式匹配):

  • 每一个字符前的字符串都有最长相等前后缀,而且最长相等前后缀的长度是我们移位的关键,所以我们单独用一个next数组存储子串的最长相等前后缀的长度。而且next数组的数值只与子串本身有关。
  • next数组作用
    • next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度。
    • 表示该处字符不匹配时应该回溯到的字符的下标
  • 事实上现在的算法已经不用next了,都是使用标准的前缀函数。它们的关系是把前缀函数整体右移一位,并在开头补 -10,就是前缀函数。
  • 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

28. 找出字符串中第一个匹配项的下标

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

双指针

双指针的典型场景之一是你想要从两端向中间迭代数组。

还有一种情况是同时有一个慢指针和一个快指针。解决这类问题的关键是:确定两个指针的移动策略。

209. 长度最小的子数组

给定一个含有 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

153. 寻找旋转排序数组中的最小值

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]

原来这书只有第一本是免费的 哈哈哈哈哈 溜了

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值