日常系列LeetCode《17·二叉树2》

Posted 常某某的好奇心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常系列LeetCode《17·二叉树2》相关的知识,希望对你有一定的参考价值。

数据规模->时间复杂度

<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)

内容

lc 662 :二叉树最大宽度
https://leetcode.cn/problems/maximum-width-of-binary-tree/
提示:
树中节点的数目范围是 [1, 3000]
-100 <= Node.val <= 100
注:两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度

#方案一:BFS
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        queue=deque()
        queue.append([root,1])
        maxv=float('-inf')
        while queue:
            size=len(queue)
            start,end=0,0
            for i in range(size):
                curr,currseq=queue.popleft()
                if i==0:start=currseq
                if i==size-1:end=currseq
                #
                if curr.left:queue.append([curr.left,2*currseq])
                if curr.right:queue.append([curr.right,2*currseq+1])
            maxv=max(maxv,end-start+1)
        return maxv

#方案二:DFS
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        if not root:return 0
        return self.DFS(root,0,1,list(),list())
    def DFS(self,node,currlevel,currseq,start,end):
        #边递,边更新存储
        if not node:return 0
        if len(start)<currlevel+1:
            start.append(currseq)
            end.append(currseq)
        else: 
            end[currlevel]=currseq
        #
        left=self.DFS(node.left,currlevel+1,2*currseq,start,end)
        right=self.DFS(node.right,currlevel+1,2*currseq+1,start,end)
        #边回溯,边计算最大宽度
        curr_width=end[currlevel]-start[currlevel]+1
        return max(curr_width,max(left,right))

lc 222 :完全二叉树的节点个数
https://leetcode.cn/problems/count-complete-tree-nodes/
提示:
树中节点的数目范围是[0, 5 * 10^4]
0 <= Node.val <= 5 * 10^4
题目数据保证输入的树是 完全二叉树
进阶:
遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?

#方案一:DFS
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:return 0
        return self.preorder(root)
    
    def preorder(self,node):
        if not node:return 0 
        #
        left=self.countNodes(node.left)
        right=self.countNodes(node.right)
        return left+right+1
#方案二:二分查找(优化)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:return 0
        #统计层数(完全二叉树)
        level=0
        curr=root
        while curr.left:
            level+=1
            curr=curr.left
        #节点个数【2^level,2^(level+1)-1】
        left,right=1<<level,(1<<(level+1))-1
        while left<right:
            mid=left+(right-left+1)//2 #+1
            if self.exsit(root,level,mid):
                left=mid #
            else:right=mid-1
        return left
        
    def exsit(self,node,level,mid):
        mask=1<<(level-1) #决定走向:例如level=4,01000
        #从root开始走
        while node and mask>0:
            if (mask&mid)==0: 
                #左行
                node=node.left
            else:
                node=node.right
            mask>>=1
        return node!=None

lc 114【top100】:二叉树展开为链表
https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/
提示:
树中结点数在范围 [0, 2000] 内
-100 <= Node.val <= 100
进阶:
你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

#方案一;先前序遍历后串联
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:return None
        #
        res=list()
        self.preorder(root,res)
        for i in range(1,len(res)):
            curr=res[i-1]
            next=res[i]
            curr.left=None
            curr.right=next

    
    def preorder(self,node,res):
        if not node: return None
        res.append(node) 
        self.preorder(node.left,res)
        self.preorder(node.right,res)
        
#方案二:边遍历边串联
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:return None
        #
        stack=[]
        stack.append(root)
        prev=None
        while stack:
            #key
            curr=stack.pop()
            if prev:
                prev.left=None
                prev.right=curr
            prev=curr
            #
            if curr.right:stack.append(curr.right)
            if curr.left:stack.append(curr.left)
        

#方案三:原地改变指针(优化)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        if not root:return None
        #
        curr=root
        while curr:
            left=curr.left
            if left:
                pre=curr.left
                while pre.right:pre=pre.right
                pre.right=curr.right
                #
                curr.left=None
                curr.right=left
                #
                curr=curr.right
            else:curr=curr.right

lc 236【剑指 68-2】【top100】:二叉树的最近公共祖先
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
提示:
树中节点数目在范围 [2, 10^5] 内。
-10^9 <= Node.val <= 10^9
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。

#方案一:维护节点与后节点关系+前序遍历
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:return None
        #
        self.par=
        self.dfs(root)
        #
        self.set=set()
        while p:
            self.set.add(p)
            p=self.par.get(p.val,None)
        while q:
            if q in self.set:return q
            q=self.par.get(q.val) #self.par[q.val]
        #
        return None

    
    def dfs(self,node):
        if not node:return None
        #
        if node.left:self.par[node.left.val]=node
        if node.right:self.par[node.right.val]=node
        #
        self.dfs(node.left)
        self.dfs(node.right)

#方案二:后序遍历(相遇时的情形)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:return None
        if root==p or root==q:return root
        #
        left=self.lowestCommonAncestor(root.left,p,q)
        right=self.lowestCommonAncestor(root.right,p,q)
        if not left:return right
        if not right:return left
        return root       

回溯思想
#回溯树的DFS
#回溯图的DFS
#本质:穷举

lc 112 :路径总和
https://leetcode.cn/problems/path-sum/
提示:
树中节点的数目在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

#方案一:回溯穷举所有路径+判断是否存在路径和
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        res=self.allpath(root)
        for sinpath in res:
            suma=sum(sinpath)
            if suma==targetSum:return True 
        return False


    def allpath(self,root):
        self.res=[] #所有路径
        path=[]
        self.dfs(root,path)
        return self.res

    def dfs(self,node,path):  
        if not node:return None
        #
        path.append(node.val)
        if not node.left and not node.right:
            self.res.append(path.copy()) #path与res不能同一个对象
        #
        self.dfs(node.left,path)
        self.dfs(node.right,path)
        #在回溯过程中,将当前节点删去
        del(path[-1]) #path.pop()
        
#方案二:计算每个路径和
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        res=self.allpath(root)
        for val in res:
            if val==targetSum:return True 
        return False


    def allpath(self,root):
        self.res=[] #所有路径和
        self.dfs(root,0)
        return self.res

    def dfs(self,node,parantpathsum):  
        if not node:return 
        #
        currpathsum=parantpathsum+node.val
        if not node.left and not node.right:
            self.res.append(currpathsum) #path与res不能同一个对象
        #
        self.dfs(node.left,currpathsum)
        self.dfs(node.right,currpathsum)
#方案四:计算每个目标和
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        res=self.allpath(root,targetSum)
        for val in res:
            if val==0:return True #val==targetSum
        return False


    def allpath(self,root,target):
        self.res=[] #所有路径和
        self.dfs(root,target)
        return self.res

    def dfs(self,node,parantpathT):  
        if not node:return 
        #
        currpathT=parantpathT-node.val
        if not node.left and not node.right:
            self.res.append(currpathT) 
        #
        self.dfs(node.left,currpathT)
        self.dfs(node.right,currpathT)
        
#方案五:计算每个节点的目标和+提前返回(边遍历边判断)
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        return self.dfs(root,targetSum)
        
    def dfs(self,node,parantpathT):  
        if not node:return False
        #
        currpathT=parantpathT-node.val
        if not node.left and not node.right:
            return currpathT==0 
        #
        left=self.dfs(node.left,currpathT)
        if left:return True
        right=self.dfs(node.right,currpathT)
        return left | right

lc 113【剑指 34】:路径总和 II
https://leetcode.cn/problems/path-sum-ii/
提示:
树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

#方案一:
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:return []
        
        return self.allpath(root,targetSum)


    def allpath(self,node,targetSum):
        self.res=[]
        path=[]
        self.dfs(node,path,targetSum)
        return self.res
    
    def dfs(self,node,path,targetSum):
        if not node:return 
        #
        path.append(node.val)
        if not node.left and not node.right:
            if sum(path)==targetSum:  #key
                self.res.<

以上是关于日常系列LeetCode《17·二叉树2》的主要内容,如果未能解决你的问题,请参考以下文章

日常系列LeetCode《16·二叉树1》

Leecode 222. 完全二叉树的节点个数——Leecode日常刷题系列

Leecode 222. 完全二叉树的节点个数——Leecode日常刷题系列

二分法万能模板Leecode 222. 完全二叉树的节点个数——Leecode日常刷题系列

LeetCode 2049统计最高分的节点数目[dfs 二叉树] HERODING的LeetCode之路

leetcode-26双周赛-5398-统计二叉树中好结点的数目