剑指offer【二叉树搜索】

整体的逻辑是在当前节点进行左右子树的迭代
基础stopcase: 上一个节点为叶子结点,本次node为空

二叉树深度

DFS 后序遍历

  • stopcase是当前为null,返回0
  • 当前node的深度为 max(左深度,右深度)+ 自己1
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        # stopcase
        if not root:
            return 0
        left_depth = self.maxDepth(root.left)
        right_depth = self.maxDepth(root.right)
        # 实际深度是左右两个子树,深的那个+1(本节点)
        return max(left_depth,right_depth)+1

BFS 层序遍历

  • 使用queue来实现,每遍历一层,depth+1
  • 直到遍历完成,返回depth
  • queue存的当上一层所有的node,依次pop并记录它们的children
  • 把这些children放到cur_row里面,等queue空了之后替代queue;depth+=1
  • 直到cur_row空了,queue空了,遍历完成,直接返回depth
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        # basecase
        if not root: return 0
        queue = [root]
        cur_depth = 0
        while queue:
            cur_row = [] # 记录本层的所有node
            for node in queue: # 把上一层的所有子节点放到本层的list里
                if node.left: cur_row.append(node.left)
                if node.right: cur_row.append(node.right)
            # 更新queue为本层的node list
            queue = cur_row
            # 深度+1
            cur_depth += 1
        return cur_depth

判断是否为平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

  • 自底向上的进行判断,对于某个节点,如果不平衡返回-1;以此进行剪枝
  • 方法同二叉树找深度,如果左右任一深度为-1,剪枝,直接返回-1
  • 进行当前节点的平衡判断,如果平衡return 深度,否返回-1
  • 最终root的return值如果是-1即为不平衡,其他值即为平衡
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def recur(root):
            # stop case
            if not root:
                return 0
            # 利用-1 剪枝
            left_depth = recur(root.left)
            right_depth = recur(root.right)
            if left_depth == -1 or right_depth == -1:
                return -1

            # 当前阶段不平衡
            elif abs(left_depth - right_depth) > 1: 
                return -1
            # 当前节点平衡了,把depth return
            else:
                return max(left_depth,right_depth)+1

        return recur(root)!= -1

二叉树中和为某值的路径

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。

  • 迭代参数:当前节点,剩余的targetsum
  • 停止条件:当前为叶子且剩余target = 0
  • 整体思路:通过recur函数遍历并记录所有的path,通过剩余target来确认是否是要找的那条,如果是,直接append到result里面
    有点不明白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 pathSum(self, root: TreeNode, target: int) -> List[List[int]]:
        result = []
        path = []

        def recur(node, tar):
            # 终止情况1: 上一个是叶节点,本次node为空
            if not node:
                return 
            # 否则正常把当前值放到path里面,并且计算余下的target
            path.append(node.val)
            tar -= node.val

            # 终止条件:如果不剩tar了,且当前是叶子节点,返回path
            if tar == 0 and not node.left and not node.right:
                result.append(list(path))
                path.pop()
                
            else: # 继续迭代
                recur(node.left,tar)
                recur(node.right,tar)
                path.pop()
                
                
        recur(root,target)
        return result

二叉树转双向列表(有序)

  • 有序的实现方式为中序遍历(左、根、右)
def dfs(root):
    if not root: return
    dfs(root.left)  # 左
    print(root.val) # 根
    dfs(root.right) # 右
  • 通过pre,cur指针构建双向列表;pre.right = cur cur.left = pre; 更新 cur = pre
  • 全局变量self.pre用于记录上一个点的信息,每次更新迭代
"""
# Definition for a Node.
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
"""
class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        # 初始化pre指针

        self.pre = None
        self.head = None

        def dfs(cur):
            if not cur:
                return
            
            dfs(cur.left) # 左子树

            # 对于当前节点,构建到双向链表中
            if not self.pre: # 如果是第一个,记录一下head
                self.head = cur
            else: # 构建,插入进去
                self.pre.right = cur
                cur.left = self.pre
            # 更新全局变量pre
            self.pre = cur
            
            dfs(cur.right) # 右子树

        if not root: return #如果树为空,返回空

        dfs(root)
        self.head.left, self.pre.right = self.pre, self.head # 最终首尾相连(pre是最后一个元素)

        return self.head

二叉搜索树的第 k 大节点

  • 中序倒叙遍历(右中左),记录index,第k个直接返回
  • 注意如果是 k-= 1, 第k个时, k=1
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        def dfs(root):
            if not root or self.index <= 0:return
            dfs(root.right)
            if self.index == 1:
                self.result = root.val
            self.index -= 1
            dfs(root.left)
        
        self.index = k
        self.result = None
        dfs(root)
        return self.result

二叉树最近的公共祖先

最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

  • p、q公共祖先有且仅有三种情况
    ** p、q分别在一个node的左右两个子树中
    ** q=root,p在q的某个子树中
    ** p=root,q在p的某个子树中

你可能感兴趣的:(剑指offer【二叉树搜索】)