5.17 位运算 滑动窗口(一) 删除二叉搜索树中节点(重要 450)

50. Pow(x, n)
在这里插入图片描述
快速幂算法
n为负数,是x**n的倒数
从x开始,每一次都对上一项进行平方,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def myPow(self, x: float, n: int) -> float:
        def quick(N):
            if N==0:
                return 1
            y=quick(N//2)
            return y*y if N%2==0 else y*y*x
        return quick(n) if n>0 else 1.0/quick(abs(n))

法二:
在这里插入图片描述
在这里插入图片描述

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if x==0:
            return 0.0
        res=1
        if n<0:
            x,n=1/x,-n
        while n:
            if n&1==1:
                res*=x
            x*=x #x=x**2
            n>>=1 #n=n//2
        return res

法三:
在这里插入图片描述

class Solution:
    def myPow(self, x: float, n: int) -> float:
        if n==0:
            return 1
        if n<0:
            x=1/x
            n=-n
        if n%2:
            return x*self.myPow(x,n-1)
        return self.myPow(x**2,n//2)

372. 超级次方
在这里插入图片描述
https://leetcode-cn.com/problems/super-pow/solution/you-qian-ru-shen-kuai-su-mi-suan-fa-xiang-jie-by-l/
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def superPow(self, a: int, b: List[int]) -> int:
        if not b:
            return 1
        base=1337
        def mulpty(x,n):
            nonlocal base
            if n==0:
                return 1
            res=1
            #对因子求模
            x%=base
            for i in range(n):
                res*=x
                res%=base
            return res
        if b:
            n1=b.pop()
        #依次弹出数组的最后一个元素,分成两部分相乘
        part1=mulpty(a,n1)
        part2=mulpty(self.superPow(a,b),10)
        #对乘法两部分因子取模
        return (part1*part2)%base
class Solution:
    def superPow(self, a: int, b: List[int]) -> int:
        if not b:
            return 1
        base=1337
        def mulpty(x,n):
            nonlocal base
            if n==0:
                return 1
            #对因子求模
            x%=base
            #采用二分法求x的n次方
            if n%2==1:
                return x*mulpty(x,n-1)
            return mulpty(x*x,n//2)
        if b:
            n1=b.pop()
        #依次弹出数组的最后一个元素,分成两部分相乘
        part1=mulpty(a,n1)
        part2=mulpty(self.superPow(a,b),10)
        #对乘法两部分因子取模
        return (part1*part2)%base

450 删除二叉搜索树中节点
在这里插入图片描述
在这里插入图片描述
用前序节点和后继节点值取代有子树的根节点,然后递归删除叶子结点

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    #后继节点 根节点右子树中第一个大于根节点的值,即中序遍历跟在根节点后面的值
    def successor(self,root):
        root=root.right
        while root.left:
            root=root.left
        return root.val
    #前驱节点 中序遍历在根节点前面的值 
    def predecessor(self,root):
        root=root.left
        while root.right:
            root=root.right
        return root.val
    def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
        if not root:
            return 
        #  要删除的节点在右子树
        if key>root.val:
            root.right=self.deleteNode(root.right,key)
        # 要删除的节点在左子树
        elif key<root.val:
            root.left=self.deleteNode(root.left,key)
        # 找到需要删除的节点
        else:
            #叶子结点直接赋值None
            if not root.left and not root.right:
                root=None
            # 存在右子树(左子树存不存在都可以),用后继节点值替换,然后删除右子树中的后继节点
            elif root.right:
                root.val=self.successor(root)
                root.right=self.deleteNode(root.right,root.val)
            # 只存在左子树,用前驱节点值替换,然后删除左子树中的前驱节点
            elif root.left:
                root.val=self.predecessor(root)
                root.left=self.deleteNode(root.left,root.val)
        return root

滑动窗口
3.无重复字符的最长子串

在这里插入图片描述
hashmap对于不存在的初始化为0
对于第一个字符,如果写成l=max(l,hash[s[r]]+1),l会变成1,r会小于l

class Solution:
    def lengthOfLongestSubstring(self, s) -> int:
        l=0
        maxl=0
        #记录每个字符的索引
        hash=defaultdict(int)
        for r in range(len(s)):
            #如果该字符第二次出现,那么上一次出现的索引一定在r的左面,判断是否在l的右面,如果在l右面则更新l,否则l不用变,更新L时将l移到重复字符索引的下一位
            l=max(l,hash[s[r]])
            hash[s[r]]=r+1
            maxl=max(maxl,r-l+1)
        return maxl

滑动窗口万能模板:
当出现重复字符时,缩小窗口到符合要求,
然后窗口向右扩张

class Solution:
    def lengthOfLongestSubstring(self, s) -> int:
        l=0
        maxl=0
        #用set记录已经出现的字符
        lookup=set()
        #记录每个字符的索引
        for r in range(len(s)):
            while s[r] in lookup:
                lookup.remove(s[l])
                l+=1
            lookup.add(s[r])
            maxl=max(r-l+1,maxl)
        return maxl

76. 最小覆盖子串(滑动窗口)
在这里插入图片描述

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        #建立字符串t的字符表
        hash1=defaultdict(int)
        #保存滑动窗口内的字符串字符表
        hash2=defaultdict(int)
        for i in t:
            if i in hash1:
                hash1[i]+=1
            else:
                hash1[i]=1
         #不能直接len(t),可能存在重复字符
        required=len(hash1)
        #最小子串长度
        minl=float('inf'),None,None
        #match 记录窗口中满足的字符个数
        l,match=0,0
        #通过r不断右移来扩张窗口
        for r in range(len(s)):
            hash2[s[r]]+=1
            if s[r] in hash1 and hash1[s[r]]==hash2[s[r]]:
                match+=1
             #当t中所有字符都在滑动窗口的字符串中,那么如果可以收缩窗口,就收缩窗口
            while l<=r and match==required:
                if r-l+1<minl[0]:
                #同时记录符合标记的最短字符串的起始索引
                    minl=(r-l+1,l,r)
                 #l右移,缩小窗口,不管s[l]在不在hash1中
                hash2[s[l]]-=1
                #如果s[l]在hash1中,那么判断此时这个字符是否还匹配,
                if s[l] in hash1 and hash2[s[l]]<hash1[s[l]]:
                        match-=1
            #不管s[l]在不在hash1中,都需要将left右移,因为此时的window的字符个数必然多于needs的字符个数
                l+=1
        return '' if minl[0]==float('inf') else s[minl[1]:minl[2]+1]

209 长度最小子数组:(滑动窗口)
在这里插入图片描述

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l,count,minl=0,0,float('inf')
        for r in range(len(nums)):
            count+=nums[r]
            #子数组和满足要求是,考虑缩小窗口,但是要保证在满足条件的情况下
            while l<=r and count>=s:
                count-=nums[l]
                minl=min(minl,r-l+1)
                l+=1
        return 0 if minl==float('inf') else minl

面试题57 - II. 和为s的连续正数序列(滑动窗口)
在这里插入图片描述

class Solution:
    def findContinuousSequence(self, target: int) -> List[List[int]]:
        res=[]
        l,r=1,2
        suma=0
        while l<r and r<=target//2+1:
            # sum=((r-l+1)*(r+l))/2
            suma=sum(list(range(l,r+1)))
            if suma<target:
                r+=1
            elif suma>target:
                l+=1
            else:
                res.append([i for i in range(l,r+1)])
                l+=1
                #正常求得满足区间时,r右移即可,但是这个递增数列,以l为开始的数组一定不符合条件,故可以一起右移
                r+=1
        return res

567 字符串的排列
在这里插入图片描述
可能写的麻烦,但是是滑动窗口这种字符题的标准格式

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        if not s1:
            return True
        #构造模式字符串字符表
        hash1=defaultdict(int)
        #记录滑动窗口内元素的字符表
        hash2=defaultdict(int)
        for s in s1:
            hash1[s]+=1
        l=0
        #记录匹配成功的元素个数
        match=0
        required=len(hash1)
        for r in range(len(s2)):
            hash2[s2[r]]+=1
            if s2[r] in hash1 and hash1[s2[r]]==hash2[s2[r]]:
                match+=1
             #当窗口内的元素满足要求了,开始缩小窗口 
            while match==required and l<=r:
            #当存在元素符合要求的字符串,且长度一致时,说明是S1的一个排列
                if len(s1)==r-l+1:
                    return True
                hash2[s2[l]]-=1
                if hash2[s2[l]]<hash1[s2[l]]:
                    match-=1
                l+=1
        #遍历所有窗口都没有找到,就返回False
        return False

438. 找到字符串中所有字母异位词 (滑动窗口)
在这里插入图片描述
同567 ,只是符合条件的记录左边界,需要全部遍历

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        hash1=defaultdict(int)
        hash2=defaultdict(int)
        for i in p:
            hash1[i]+=1
        l,required=0,len(hash1)
        match=0
        res=[]
        for r in range(len(s)):
            hash2[s[r]]+=1
            if hash1[s[r]]==hash2[s[r]]:
                match+=1
            while l<=r and match==required:
                if r-l+1==len(p):
                    res.append(l)
                hash2[s[l]]-=1
                if hash2[s[l]]<hash1[s[l]]:
                    match-=1
                l+=1
        return res

242. 有效的字母异位词
在这里插入图片描述
如果输入字符包含unicode,使用哈希表而不是固定大小的计数器。分配一个大的数组来适应整个 Unicode 字符范围,这个范围可能超过 100万。哈希表是一种更通用的解决方案,可以适应任何字符范围。

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        if len(s)!=len(t):
            return False
        hash2,hash1=defaultdict(int),defaultdict(int)
        for i in s:
            hash1[i]+=1
        for j in t:
            hash2[j]+=1
        return hash1==hash2

49. 字母异位词分组
在这里插入图片描述
法一:排序数组分类
当且仅当它们的排序字符串相等时,两个字符串是字母异位词。
将键存储为散列化元组
在这里插入图片描述
在这里插入图片描述

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        ans=defaultdict(list)
        res=[]
        for s in strs:
            ans[tuple(sorted(s))].append(s)
        for key,values in ans.items():
            res.append(values)
        return res

法二:按计数分类
当且仅当它们的字符计数(每个字符的出现次数)相同时,两个字符串是字母异位词
上面的排序比较费时间
在这里插入图片描述

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        res=defaultdict(list)
        for s in strs:
            #将count换成哈希表计数,还是会打乱顺序需要排序
            count=[0]*26
            for c in s:
                count[ord(c)-ord('a')]+=1
            res[tuple(count)].append(s)
        result=[]
        for key,values in res.items():
            result.append(values)
        return result

面试题14-二 剪绳子二
在这里插入图片描述
范围较大,可能会越界
动态规划:

class Solution:
    def cuttingRope(self, n: int) -> int:
        #dp 记录长度为i时的最大乘积
        # 2,3需要单独计算
        if n==2:
            return 1
        if n==3:
            return 2
        dp=[0,1,2,3]
        for i in range(4,n+1):
            maxm=0
            for j in range(1,i//2+1):
                maxm=max(maxm,dp[j]*dp[i-j])
            dp.append(maxm)
        return dp[-1]%1000000007

贪心:
在这里插入图片描述
3:3>1*2
为使乘积最大,只有长度为 2 和 3 的绳子不应再切分,且 3比 2 更优 ,剪绳子数学问题其实就是尽可能多地切3的片段
在这里插入图片描述
在这里插入图片描述

class Solution:
    def cuttingRope(self, n: int) -> int:
        #n<=3时,因为要求必须切割两段以上
        if n==2:
            return 1
        if n==3:
            return 2
        if n==4:
            return 4
        res=1
        while n>4:
            res*=3
            res%=1000000007#大数问题,考虑在每一步取余
            n-=3#尽可能多的以长度3分成多段时,乘积最大
        return res*n%1000000007

面试题14- I. 剪绳子
在这里插入图片描述
这个没有大数要求

class Solution:
    def cuttingRope(self, n: int) -> int:
        if n==2:
            return 1
        if n==3:
            return 2
        #dp=[0,1,2,3]
        #for i in range(4,n+1):
            #maxn=0
            #for j in range(1,i):
                #maxn=max(maxn,dp[j]*dp[i-j])
            #dp.append(maxn)
        #return dp[-1]
        if n==4:
            return 4
        res=1
        while n>4:
            res*=3
            n-=3
        return n*res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值