Python二叉树总结(二)


对称二叉树

思路:比较根节点的左右子树是否翻转

递归做法:1. 先判断None的情况 2.然后判断左右节点数值的情况
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return None
        return self.comper(root.left, root.right)
    
    def comper(self, left, right):
        if left == None and right != None: return False
        elif left != None and right == None: return False
        elif left == None and right == None : return True
        elif left.val != right.val: return False
        else:
            outside = self.comper(left.left, right.right)
            inside = self.comper(left.right, right.left)
            is_same = outside and inside
            return is_same
迭代法:用队列
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return None
        
        from collections import deque

        que = deque([root.left, root.right])

        while que:
            first_node = que.popleft()
            second_node = que.popleft()

            if not first_node and not second_node:
                continue
            
            if not first_node or not second_node or first_node.val != second_node.val:
                return False
            
            que.append(first_node.left)
            que.append(second_node.right)
            que.append(first_node.right)
            que.append(second_node.left)

        return True
迭代: 用栈
class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return None
        
        stack = [root.right, root.left]


        while stack:
            left_node = stack.pop()
            right_node = stack.pop()

            if not left_node and not right_node:
                continue
            
            if not left_node or not right_node or left_node.val != right_node.val:
                return False
            
            stack.append(left_node.right)        
            stack.append(right_node.left)
            stack.append(right_node.right)
            stack.append(left_node.left)

        return True

完全二叉树节点

普通二叉树求节点:

递归解法:
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        return self.getNodeSum(root)
    
    def getNodeSum(self, node):
        if not node:
            return 0
        
        left_sum = self.getNodeSum(node.left)
        right_sum = self.getNodeSum(node.right)

        return left_sum + right_sum + 1  # 加一是中间节点
迭代
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0

        result = 0
        
        from collections import deque
        que = deque([root])

        while que:
            node = que.pop()
            result += 1
            
            if node.left:
                que.append(node.left)
            if node.right:
                que.append(node.right)
        
        return result

完全二叉树的解法:

# 递归:
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        left = root.left
        right = root.right

        left_high = 1
        right_high = 1

        while left:
            left = left.left
            left_high += 1
        while right:
            right = right.right
            right_high += 1
        
        if left_high == right_high:
            tree_sum = 2 ** left_high - 1
            return tree_sum
            
        return self.countNodes(root.left) + self.countNodes(root.right) + 1

平衡二叉树

# 递归
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        if self.get_high(root) != -1:
            return True
        else:
            return False

    def get_high(self, node):
        if not node:
            return 0
        
        left_high = self.get_high(node.left)
        right_high = self.get_high(node.right)

        if left_high == -1 or right_high == -1:
            return -1
        if abs(left_high - right_high) > 1:
            return -1  
        return 1 + max(left_high, right_high)
# 迭代法:
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        if not root:
            return True
        stack = [root]
        while stack:
            node = stack.pop()
            if abs(self.get_depth(node.left) - self.get_depth(node.right)) > 1:
                return False
            
            if node.left:
                stack.append(node.left)
            if node.right:
                stack.append(node.right)

        return True

    
    def get_depth(self, root):
        if not root:
            return 0
        depth = 0
        
        from collections import deque
        que = deque([root])
        
        while que:
            size = len(que)
            depth += 1
            for _ in range(size):
                node = que.popleft()
                
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
        return depth

二叉树的所有路径

# 递归
class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        if not root:
            return []

        result = []
        path = ''
        self.traversal(root, path, result)
        return result
    
    def traversal(self, node, path, result):
        path += str(node.val)
        if not node.left and not node.right:
            result.append(path)
        
        if node.left:
            self.traversal(node.left, path + '->', result)
        if node.right:
            self.traversal(node.right, path + '->', result)
# 迭代法:
class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        if not root:
            return []
        node_stack = deque([root])
        path_stack = deque([])
        result = []
        path_stack.append(str(root.val))

        while node_stack:
            node = node_stack.popleft()
            path = path_stack.popleft()
            
            if not node.left and not node.right:
                result.append(path)
            
            if node.right:
                node_stack.append(node.right)
                path_stack.append(path + '->' + str(node.right.val))

            if node.left:
                node_stack.append(node.left)
                path_stack.append(path + '->' + str(node.left.val))
            
        return result

相同的树

class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        return self.is_same(p, q)
    
    def is_same(self, tree1, tree2):
        if not tree1 and tree2: return False
        elif tree1 and not tree2: return False
        elif not tree1 and not tree2: return True
        elif tree1.val != tree2.val: return False
        else:
            comper_left = self.is_same(tree1.left, tree2.left)
            comper_right = self.is_same(tree1.right, tree2.right)
            comper = comper_left and comper_right
        return comper

左叶子之和

# 递归:
class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        if not root: return 0

        left_tree_left_levels_sum = self.sumOfLeftLeaves(root.left)
        rirht_tree_left_levels_sum = self.sumOfLeftLeaves(root.right)

        levels_sum = 0
        if root.left and not root.left.left and not root.left.right:
            levels_sum = root.left.val
        
        return left_tree_left_levels_sum + rirht_tree_left_levels_sum + levels_sum
# 迭代:
class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        stack = [root]
        res = 0
        while stack:
            node = stack.pop()
            if node.left and not node.left.left and not node.left.right:
                res += node.left.val
            
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
        return res

找树左下角的值

class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        if not root:
            return None
        from collections import deque
        que = deque([root])

        while que:
            _len = len(que)
            for i in range(_len):
                node = que.popleft()
                if i == 0:
                    result = node.val
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right)
        return result

路径总和i

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:
            return False
        path = ''
        result = []
        self.traversal(root, path, result)
        if targetSum in result:
            return True
        else:
            return False
    
    def traversal(self, node, path, result):
        path += str(node.val)
        if not node.left and not node.right:
            result.append(sum(list(map(int, path.split('->')))))
        
        if node.left:
            self.traversal(node.left, path + '->', result)

        if node.right:
            self.traversal(node.right, path + '->', result)

总数之和ii

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root:
            return []
        path = ''
        result = []
        res = []
        self.traversal(root, path, result)
        for i in range(len(result)):
            way = list(map(int, result[i].split('->')))
            if sum(way) == targetSum:
                res.append(way)
        return res
    
    def traversal(self, node, path, result):
        path += str(node.val)
        if not node.left and not node.right:
            result.append(path)
        
        if node.left:
            self.traversal(node.left, path + '->', result)

        if node.right:
            self.traversal(node.right, path + '->', result)

从中序和后序遍历序列构造二叉树

class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
        if not inorder:
            return None
        
        head_val = postorder[-1]
        root = TreeNode(head_val)

        root_index = inorder.index(head_val)

        root.left = self.buildTree(inorder[:root_index], postorder[:root_index])
        root.right = self.buildTree(inorder[root_index + 1:], postorder[root_index: - 1])

        return root

从前序和中序遍历构造二叉树

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not preorder:
            return None
        
        head_val = preorder[0]
        root = TreeNode(head_val)

        root_index = inorder.index(head_val)

        root.left = self.buildTree(preorder[1: root_index + 1], inorder[: root_index])
        root.right = self.buildTree(preorder[root_index + 1: ], inorder[root_index + 1: ])

        return root

最大二叉树

class Solution:
    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
        if not nums:
            return None
        _max = max(nums)
        max_index = nums.index(_max)
        
        root = TreeNode(_max)

        root.left = self.constructMaximumBinaryTree(nums[:max_index])
        root.right = self.constructMaximumBinaryTree(nums[max_index + 1: ])

        return root

合并二叉树

# 递归:
class Solution:
    def mergeTrees(self, root1, root2):
        if not root1 and not root2:
            return None

        if root1 and not root2:
            return root1
        elif not root1 and root2:
            return root2
        else:
            root_val = root1.val + root2.val
            root = TreeNode(root_val)
            root.left = self.mergeTrees(root1.left, root2.left)
            root.right = self.mergeTrees(root1.right, root2.right)

        return root
迭代:注释下面的写法更简洁
class Solution:
    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
        # if not root1 and not root2:
        #     return None   
        # if root1 and not root2:
        #     return root1
        # elif not root1 and root2:
        #     return root2
        # else:
        #     que = deque([root1, root2])

        if not root1:
            return root2
        if not root2:
            return root1
        
        que = deque([root1, root2])
        

        while que:
            node1 = que.popleft()
            node2 = que.popleft()

            if node1.left and node2.left:
                que.append(node1.left)
                que.append(node2.left)
            
            if node1.right and node2.right:
                que.append(node1.right)
                que.append(node2.right)
            
            node1.val += node2.val

            if not node1.left and node2.left:
                node1.left = node2.left
            if not node1.right and node2.right:
                node1.right = node2.right

        return root1

二叉搜索树

迭代:
class Solution:
    def searchBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return None
        
        cur = root
        while cur:
            if cur.val == val: return cur
            elif cur.val > val: cur = cur.left
            else: cur = cur.right
        
        return None
# 递归:
class Solution:
    def searchBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return None
        if root.val == val: return root
		
		# 注意这里要加 return,当要搜索某条边或者某个节点时,需要加return, 不然就是遍历整棵树
        elif root.val > val:
            return self.searchBST(root.left, val)
        else:
            return self.searchBST(root.right, val)

验证二叉搜索树

不能只判断当前节点的左节点小于根节点,右节点大于根节点,而是整个左子树小于根节点,整个柚子树大于根节点

可以用中序遍历二叉数存到数组中,判断数组是否有序。

# 利用中序遍历将值放到数组中
# 这串代码一开始发现没有全部A出来,结果显示result和result_sort是一样的但是返回的是False,找不到原因
# 后来发现是这题要求二叉搜索树中值不能重复
class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if not root:
            return
        result = []
        self.traversal(root, result)
        result_sort = sorted(result)
        if len(result) == len(set(result)):
            if result == result_sort:
                return True
        return False

    def traversal(self, node, result):
        if not node:
            return
        self.traversal(node.left, result)
        result.append(node.val)
        self.traversal(node.right, result)
# 标准做法:迭代
class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if not root:
            return True
        stack = []
        cur = root
        pre = None
        while cur or stack:
            if cur:
                stack.append(cur)
                cur = cur.left
            else:
                node = stack.pop()
                cur = node
                
                if pre and cur.val <= pre.val:
                    return False
                pre = cur
                cur = cur.right
        return True

二叉搜索树的最小绝对值

class Solution:
    def getMinimumDifference(self, root: TreeNode) -> int:
        if not root:
            return None
        result = []
        self.buildlist(root, result)
        _min = []
        for i in range(1, len(result)):
            _min.append(result[i] - result[i - 1])
        return min(_min)

    def buildlist(self, node, result):
        if not node:
            return
        self.buildlist(node.left, result)
        result.append(node.val)
        self.buildlist(node.right, result)

二叉搜索树的众数

普通二叉树的做法:

  • 把树遍历
  • 用map统计频率,把频率排个序
  • 取前面高频的元素集合

二叉搜索树做法:双指针

  • 弄一个指针指向前一个节点,每次cur(当前节点)才能和pre(前一个节点)作比较
  • 初始化的时候 pre= NULL,这样当pre为NULL时,就知道这是比较的第一个元素
  • 用评率count记录元素出现频率,如果等于maxCount,就把这个元素加到结果集中
  • 如果这个maxCount不是最大频率,就让之前的元素失效
递归:
class Solution:
    def findMode(self, root: TreeNode) -> List[int]:
        self.result = []
        self.max_count = 0
        self.count = 0
        self.pre = TreeNode()
        self.searchBST(root)
        return self.result
    
    def searchBST(self, node):
        if not node:
            return None
        
        self.searchBST(node.left)  # 左
        
        # 中
        if not self.pre:
            self.count = 1
        elif self.pre.val == node.val:
            self.count += 1
        else:
            self.count = 1

        self.pre = node

        if self.count == self.max_count:
            self.result.append(node.val)
        elif self.count > self.max_count:
            self.result = [node.val]
            self.max_count = self.count
        
        self.searchBST(node.right)  # 右
# 迭代-中序遍历-不使用额外的空间,利用搜索二叉树的特性
class Solution:
    def findMode(self, root: TreeNode) -> List[int]:
        stack = []
        count, max_count = 0, 0
        result = []
        cur = root
        pre = TreeNode()
        
        while cur or stack:
            if cur:  # 指针来访问节点,访问到最底层
                stack.append(cur)
                cur = cur.left
            else:  # 逐一处理节点
                cur = stack.pop()

                if not pre:
                    count = 1
                elif pre.val == cur.val:  # 与前一个节点数值相同
                    count += 1
                else:
                    count = 1

                if count == max_count:
                    result.append(cur.val)
                elif count > max_count:
                    result = [cur.val]
                    max_count = count
                
                pre = cur
                cur = cur.right
        return result

最近公共祖先

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

        if left and right:
            return root
        if left:
            return left
        return right

二叉搜索树的最近公共祖先

从上到下找到第一个在p, q区间的数

# 递归:
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root.val > p.val and root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)
        if root.val < p.val and root.val < q.val:
            return self.lowestCommonAncestor(root.right, p, q)
        return root
# 迭代:
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while True:
            if root.val > p.val and root.val > q.val:
                root = root.left
            elif root.val < p.val and root.val < q.val:
                root = root.right
            else:
                return root

二叉搜索树的插入操作

# 递归:有返回值
class Solution:
    def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return TreeNode(val)
        
        # 这里返回的直接就是新的树
        if val < root.val:
            root.left = self.insertIntoBST(root.left, val)

        if val > root.val:
            root.right = self.insertIntoBST(root.right, val)

        return root
# 递归:无返回值
class Solution:
    def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return TreeNode(val)
        
        if not root.left and val < root.val:
            root.left = TreeNode(val)
        
        if not root.right and val > root.val:
            root.right = TreeNode(val)
        
        if val < root.val:
            self.insertIntoBST(root.left, val)
        
        if val > root.val:
            self.insertIntoBST(root.right, val)
        
        return root
迭代;
class Solution:
    def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return TreeNode(val)
        
        parent = None
        cur = root
        while cur:
            if val < cur.val:
                parent = cur
                cur = cur.left
            else:
                parent = cur
                cur = cur.right
            
        if val < parent.val:
            parent.left = TreeNode(val)
        else:
            parent.right = TreeNode(val)

        return root

删除二叉搜索树的节点

普通二叉树删除方式:用交换值的操作来删除目标节点

代码中目标节点被操作两次:

  • 第一次是和目标节点的右子树最左面节点交换
  • 第二次直接被NULL覆盖

搜索二叉树删除节点五种情况:

  • 没有找到节点,遍历到空节点返回
  • 找到节点,左右孩子都为空,直接删除节点,返回None
  • 删除节点的左孩子为空,右孩子不为空,返回右孩子根节点
  • 删除节点的右孩子为空,左孩子不为空,返回左孩子根节点
  • 左右孩子节点都不为空,将删除节点的左子树根节点放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点
class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        if not root: return root

        if root.val == key:
            if not root.left and not root.right: return None

            elif not root.left:
                tmp = root
                root = root.right
                del tmp
                return root
            
            elif not root.right:
                tmp = root
                root = root.left
                del tmp
                return root
            
            else:
                v = root.right
                while v.left:
                    v = v.left
                tmp = root
                v.left = root.left
                root = root.right
                del tmp
                return root
        
        if root.val > key:
            root.left = self.deleteNode(root.left, key)
        if root.val < key:
            root.right = self.deleteNode(root.right, key)
        return root

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

将节点2直接赋值给3

class Solution:
    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
        if not root: return None

        # 单层递归逻辑
        if root.val < low:
            return self.trimBST(root.right, low, high)

        # 若当前root节点小于左界:只考虑其右子树,用于替代更新后的其本身,抛弃其左子树整体
        if root.val > high:
            return self.trimBST(root.left, low, high)

        # 若当前root节点大于右界:只考虑其左子树,用于替代更新后的其本身,抛弃其右子树整体
        if low <= root.val <= high:
            root.left = self.trimBST(root.left, low, high)
            root.right = self.trimBST(root.right, low, high)
        # 返回更新后的剪枝过的当前节点root

        return root

将有序数组转换成二叉搜索树

构造二叉树:重点是选取数组最中间元素为分割点,左侧为递归的左区间,右侧为递归的右区间,必然是平衡树,左闭右闭区间。

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        if not nums: return None

        root = self.traversal(nums, 0, len(nums) - 1)

        return root
    
    def traversal(self, nums, left, right):
        if left > right: return None

        mid = left + (right - left) // 2

        root = TreeNode(nums[mid])
        root.left = self.traversal(nums, left, mid - 1)
        root.right = self.traversal(nums, mid + 1, right)
        return root

把二叉搜索树转换为累加树

class Solution:
    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root: return None
        self.pre = 0
        self.traversal(root)
        return root

    def traversal(self, node):
        if not node:
            return None

        self.traversal(node.right)
        self.pre += node.val
        node.val = self.pre
        self.traversal(node.left)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值