5.11力扣 回溯 负进制转换 669修剪二叉搜索树 二叉树最长交错路径 最近公共祖先 判断是都是BST(迭代好想,递归不好想) 卡特兰数

1261 在受污染的二叉树中查找元素
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
层次遍历修改数据,用集合保存数据

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class FindElements:
    def __init__(self, root: TreeNode):
        self.root=root
        self.root.val=0
        node=self.root
        #list保存数据最慢
        #使用set快一点
        self.hash=set()
        #self.hash={}
        stack=[node]
        while stack:
            for _ in range(len(stack)):
                node=stack.pop(0)
                self.hash.add(node.val)
                #self.hash[node.val]=1
                if node.left:
                    node.left.val=2*node.val+1
                    stack.append(node.left)
                if node.right:
                    node.right.val=2*node.val+2
                    stack.append(node.right)
    def find(self, target: int) -> bool:
        if target in self.hash:
            return True
        return False
# Your FindElements object will be instantiated and called as such:
# obj = FindElements(root)
# param_1 = obj.find(target)

递归更快:
在这里插入图片描述

class FindElements:
    def __init__(self, root: TreeNode):
        self.root=root
        self.root.val=0
        node=self.root
        self.hash=set()
        def dfs(root,val):
            if not root:
                return 
             #val值在上一层已经被计算好了
            root.val=val
            self.hash.add(val)
            dfs(root.left,2*val+1)
            dfs(root.right,2*val+2)
        dfs(node,0)
    def find(self, target: int) -> bool:
        if target in self.hash:
            return True
        return False

1017. 负二进制转换
在这里插入图片描述
与2进制表示法类似,当能够整除的时候该位为0,否则为1.
只是需要修改一下除数的迭代公式,正常二进制的商向下取整,负二进制商向上取整(使用math.ceil)
Math.ceil() 函数返回大于或等于一个给定数字的最小整数

import math
class Solution:
    def baseNeg2(self, N: int) -> str:
        if N==0:
            return '0'
            # N是十进制数,x是负进制
        def num_to_n_scale(N, x):
            buff = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 'A', 'B', 'C', 'D', 'E', 'F']
            res=''
            while N!=0:
                s=math.ceil(N/x)  #商
                y=N-s*x  #余数
                res=str(buff[y])+res
                N=s
            return res
        return num_to_n_scale(N,-2)

面试题26 树的子结构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        if not A or not B:
            return False
        #判断以A为根节点的子树是否与B相同
        def recur(A,B):
            if not B:
                return True
            if not A or A.val!=B.val:
                return False
            if A.val==B.val:
                return recur(A.left,B.left) and recur(A.right,B.right)
        #需要遍历A的所有节点作为根节点的子树,是否存在与B相同结构
        return recur(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)

669. 修剪二叉搜索树
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def trimBST(self, root: TreeNode, L: int, R: int) -> TreeNode:
        if not root:
            return 
         #根节点改变的两种情况
        if root.val<L:
        #修剪后的根节点一定出自右子树
            return self.trimBST(root.right,L,R)
         #修剪后的根节点一定出自左子树
        elif root.val>R:
            return self.trimBST(root.left,L,R)
        #当前根节点符合要求,根节点不变,递归判断左子树和右子树
        root.left=self.trimBST(root.left,L,R)
        root.right=self.trimBST(root.right,L,R)
        return root

226. 翻转二叉树
在这里插入图片描述

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return
        stack=[root]
        while stack:
            for _ in range(len(stack)):
                node=stack.pop(0)
                node.left,node.right=node.right,node.left
                if node.left:
                    stack.append(node.left)
                if node.right:
                    stack.append(node.right)
        return root 

二叉树中使用全局变量计算结果

1372 二叉树中的最长交错路径
在这里插入图片描述
在这里插入图片描述
递归 DFS

class Solution:
    def longestZigZag(self, root: TreeNode) -> int:
        self.maxium=0
        #我们只需要传递「当前」这个点应该走的方向(「向左」或者「向右」)dir,以及以这个点结尾的最长交错路径的长度 len
        # 0向左,1向右
        #lent是root为结尾的最长交错路径
        # direction 是当前点应该走的方向
        def dfs(root,direction,lent):
            if not root:
                return 
            self.maxium=max(self.maxium,lent)
            if direction==0:
                #如果当前点应该向左且可以向左,那么就让他向左走一步,新的 len 是当前的 len 加一
                dfs(root.left,1,lent+1)
                #如果只有右子树,则只能向右,则长度重置为1,
                dfs(root.right,0,1)
            else:
                dfs(root.right,0,lent+1)
                dfs(root.left,1,1)
        #root中没有父节点,所以长度初始化为0
        dfs(root,0,0)
        dfs(root,1,0)
        return self.maxium

动态规划 BFS

class Solution:
    def longestZigZag(self, root: TreeNode) -> int:
        if not root:
            return 0
        #记 f(u)为从根到节点 u 的路径上以 u 结尾并且 u 是它父亲的左儿子的最长交错路径,g(u) 为从根到节点 u 的路径上以 u 结尾并且 u 是它父亲的右儿子的最长交错路径。
        f,g=defaultdict(int),defaultdict(int)
        stack=deque()
        stack.append((root,None))
        f[root],g[root]=0,0
        maxium=0
        while stack:
            for _ in range(len(stack)):
                node,pre=stack.popleft()
                if pre:
                    if node==pre.left:
                        g[node]=f[pre]+1
                    else:
                        f[node]=g[pre]+1
                if node.left:
                    stack.append((node.left,node))
                if node.right:
                    stack.append((node.right,node))
        for _,maxf in f.items():
            maxium=max(maxium,maxf)
        for _ , maxg in g.items():
            maxium=max(maxium,maxg)
        return maxium

814 二叉树剪枝
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
python中函数里引用,树是不能直接整棵树级别的=none的 这样不会修改原变量(对象),只有修改子树或结点的值是会影响到root的,所以在判断完这个子树要删除最好返回一个标记,再上一层rode.left/right = None是可以修改到原变量的,所以题解也是改子树而不是传进来的整棵树

class Solution:
    def pruneTree(self, root: TreeNode) -> TreeNode:
        # 包含1 返回True
        # 不包含1,则返回False,且将不满足条件的子树置空
        def dfs(root):
            if not root:
                return False
            flagf=dfs(root.left)
            flagr=dfs(root.right)
            if not flagf:
                root.left=None
            if not flagr:
                root.right=None
            return root.val==1 or flagf or flagr
        if dfs(root):
            return root
        else:
            return None

1123 最深叶节点的最近公共祖先
同865
在这里插入图片描述
我们可以看出最近公共祖先的两个子树是等高的,如果不等高,那么高度较小的那个子树叶结点必然不是最深。
我们可以设计这样的深度优先搜索算法,每一层返回值有两部分组成:一部分是以该结点为根的子树中,最深叶结点的公共祖先,另一部分是该层的高度(也即该结点到其最深叶结点的深度)
在这里插入图片描述

class Solution:
    def lcaDeepestLeaves(self, root: TreeNode) -> TreeNode:
        def dfs(root):
            if not root:
                return None,0
            #公共祖先,当前节点作为根节点的子树最大深度
            l,ld=dfs(root.left)
            r,rd=dfs(root.right)
            #左右子树深度相同,说明该点为最深叶节点的最近公共祖先
            if ld==rd:
                return root,ld+1
            elif ld<rd:
                return r,rd+1
            else:
                return l,ld+1
        node,depth=dfs(root)
        return node

865. 具有所有最深结点的最小子树
在这里插入图片描述

class Solution:
    def subtreeWithAllDeepest(self, root: TreeNode) -> TreeNode:
        def dfs(root):
            if not root:
                return 0,None
            left,lr=dfs(root.left)
            right,rr=dfs(root.right)
            if left==right:
                return left+1,root
            elif left<right:
                return right+1,rr
            else:
                return left+1,lr
        depth,node=dfs(root)
        return node

验证是否是二叉搜索树:
面试题 04.05
98

在这里插入图片描述
迭代:

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if not root:
            return True
        stack=[]
        node=root
        pre=float('-inf')
        while stack or node:
            while node:
                stack.append(node)
                node=node.left
            node=stack.pop()
            if node.val<=pre:
                return False
            pre=node.val
            node=node.right
        return True

递归:

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if not root:
            return True
        def dfs(node,left,right):
            if not node:
                return True
            if left<node.val<right:
                return dfs(node.left,left,node.val) and dfs(node.right,node.val,right)
            return False
        return dfs(root,float('-inf'),float('inf'))

面试题 34 二叉树中和为某一值的路径
在这里插入图片描述

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        self.hash=defaultdict(list)
        def dfs(root,res,sumval):
            if not root:
                return None
               #到达根节点时,将该路径的和及对应路径加入到哈希表中
            if not root.left and not root.right:
                self.hash[sumval+root.val].append(res+[root.val])
               #不到叶子结点,则继续向左向右遍历
            dfs(root.left,res+[root.val],sumval+root.val) 
            dfs(root.right,res+[root.val],sumval+root.val)
        dfs(root,[],0)
        return self.hash[sum]

卡特兰数
96 不同的二叉搜索树:
在这里插入图片描述
在这里插入图片描述

class Solution:
    def numTrees(self, n: int) -> int:
        if n==0:return 1
        ## dp[i]:以1..i为节点组成的二叉搜索树的个数
        dp=[0]*(n+1)
        dp[0],dp[1]=1,1
        for i in range(2,n+1):
            for j in range(i):
                dp[i]+=dp[j]*dp[i-j-1]
        return dp[n]

N对括号正确匹配数目

面试题 08.09 括号
在这里插入图片描述
在匹配过程中不能出现剩余左括号数目多于剩余右括号

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        #p是剩余( 的个数,q是剩余)的个数
        res=[]
        def dfs(p,q,ans):
            # 如果剩下的左括号比右括号多,则匹配不成功
            if p>q:
                return
            if p==0 and q==0:
                res.append(ans)
            #优先匹配左括号
            if p>0:
                dfs(p-1,q,ans+'(')
            if q>0:
                dfs(p,q-1,ans+')')
        dfs(n,n,'')
        return res

n=3:在这里插入图片描述

字符串加法:乘法2
43 字符串相乘
在这里插入图片描述
在这里插入图片描述

class Solution:
    def multiply(self, num1: str, num2: str) -> str:
        if num1=='0' or num2=='0':
            return '0'
        n1=len(num1)
        n2=len(num2)
        res=[0]*(n1+n2)
        #将对应位数乘积保存到数组中
        for i in range(n1-1,-1,-1):
            for j in range(n2-1,-1,-1):
            #字符转换成数字
                cur=(ord(num1[i])-ord('0'))*(ord(num2[j])-ord('0'))
                res[i+j]+=cur//10 #商
                res[i+j+1]+=cur%10 #余数
        for i in range(n1+n2-1,-1,-1):
            flag=res[i]//10
            res[i-1]+=flag
            res[i]=res[i]%10
        return ''.join([str(i) for i in res]).lstrip('0')

415 字符串相加
在这里插入图片描述

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        if num1=='0' and num2=='0':
            return '0'
        n=max(len(num1),len(num2))
        num1=num1.rjust(n,'0')
        num2=num2.rjust(n,'0')
        res=[0]*(n+1)
        i=n-1
        while i>=0:
            cur=ord(num1[i])-ord('0')+ord(num2[i])-ord('0')
            res[i]+=cur//10
            res[i+1]+=cur%10
            i-=1
        for i in range(n,-1,-1):
            flag=res[i]//10
            res[i-1]+=flag
            res[i]=res[i]%10
        return ''.join([str(i) for i in res]).lstrip('0')

2.两数相加
在这里插入图片描述

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        root=ListNode(0)
        tmp=root
        flag=0
        while l1 or l2:
            x=l1.val if l1 else 0
            y=l2.val if l2 else 0
            cur=x+y+flag
            tmp.next=ListNode(cur%10)
            flag=cur//10
            if l1:l1=l1.next
            if l2:l2=l2.next
            tmp=tmp.next
        if flag==1:
            tmp.next=ListNode(flag)
        return root.next

445 两数相加二
在这里插入图片描述
数据入栈,从前往后构造链表

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        stack1,stack2=[],[]
        root=ListNode(0)
        tmp=root
        while l1 or l2:
            if l1:
                stack1.append(l1.val)
                l1=l1.next
            if l2:
                stack2.append(l2.val)
                l2=l2.next
        res=[]
        flag=0
        while stack1 or stack2:
            x=stack1.pop() if stack1 else 0
            y=stack2.pop() if stack2 else 0
            cur=x+y+flag
            flag=cur//10
            res.append(cur%10)
        res.append(flag)
        if res[-1]==0:
            res=res[:-1]
        for i in res[::-1]:
            tmp.next=ListNode(i)
            tmp=tmp.next
        return root.next

从后往前构造链表

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        stack1,stack2=[],[]
        root=ListNode(0)
        tmp=root
        while l1 or l2:
            if l1:
                stack1.append(l1.val)
                l1=l1.next
            if l2:
                stack2.append(l2.val)
                l2=l2.next
        res=[]
        flag=0
        ans=None
        while stack1 or stack2 or flag!=0:
            x=stack1.pop() if stack1 else 0
            y=stack2.pop() if stack2 else 0
            cur=x+y+flag
            flag=cur//10
            #从后往前构造链表
            cur=ListNode(cur%10)
            cur.next=ans
            ans=cur
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值