LeetCode-Python 树专题(学习笔记+代码)

LeetCode144二叉树的前序遍历

LeetCode94二叉树中序遍历

LeetCode145二叉树后序遍历

先序遍历:
即先访问节点(Node)本身,然后访问左(left subtree)、右子树(right subtree)
中序遍历:
即先访问左子树、然后再访问节点,最后访问节点。
后序遍历:
先访问左子树、在访问右子树,最后访问节点。
在这里插入图片描述

递归

class Node:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left # 左子树
        self.right = right # 右子树      

# -*- coding: utf-8 -*-
class Node:
    def __init__(self,value=None,left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

	def preTraverse(root):
	    # 前序遍历
	    if root == None:
	        return
	    print(root.value, end=' ')
	    preTraverse(root.left)
	    preTraverse(root.right)
	
	def midTraverse(root):
	    # 中序遍历
	    if root == None:
	        return
	    midTraverse(root.left)
	    print(root.value, end=' ')
	    midTraverse(root.right)
	
	def afterTraverse(root):
	    # 后序遍历
	    if root == None:
	        return
	    afterTraverse(root.left)
	    afterTraverse(root.right)
	    print(root.value, end=' ')

# 测试:
if __name__ == '__main__':
    root = Node()
    root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
    print('前序遍历:')
    preTraverse(root)
    print('\n中序遍历:')
    midTraverse(root)
    print('\n后序遍历:')
    afterTraverse(root)


栈方法

# # -*- coding: utf-8 -*-
class Node:
    def __init__(self, value=None, left=None, right=None):
        self.value = value
        self.left = left
        self.right = right

    def preTraverse(self):
        """
        使用栈结构实现先序遍历的思路:先将该二叉树整体推入到栈中,
        根据栈后进先出的特性,先将栈取出:打印输出该二叉树的值,
        因此需要先将二叉树的右节点推入栈结构中(如果存在的话)
        然后再将二叉树的左节点推入栈中(如果存在的话)
        下一次从栈中取的话就能达到先去左节点,后取右节点的效果。
        """
        if self.value == None:
            return
        stack = [self]
        while stack:
            current = stack.pop()
            print(current.value, end=' ')
            if current.right:
                stack.append(current.right)
            if current.left:
                stack.append(current.left)

    def midTraverse(self):
        """
        中序遍历需要执行打印顺序为:左子树、节点、右子树
        需要先找到该二叉树的的最小左子树,然后从这颗左子树开始遍历节点和右子树
        """
        if self.value == None:
            return
        stack = []
        current = self
        while len(stack) != 0 or current:
            if current:  # 不断递进,直到找到当前树的最小左子树
                stack.append(current)
                current = current.left
            else:  # 当前的栈中末尾的树已经是最小树时
                temp = stack.pop()
                print(temp.value, end=' ')  # 打印出了当前树的节点后,开始对右子树动刀子
                current = temp.right

    def afterTraverse(self):
        if self.value == None:
            return
        stack1 = [self]
        stack2 = []
        #
        while stack1:  # 使用了两个栈进行存储,因此从两个栈就构成了一个队列,先进先出
            current = stack1.pop()
            stack2.append(current)
            if current.left:
                stack1.append(current.left)
            if current.right:
                stack1.append(current.right)
        # 直接遍历stack2输出即可:
        while stack2:
            print(stack2.pop().value, end=' ')

# 测试:
if __name__ == '__main__':
    root = Node('D', Node('B', Node('A'), Node('C')), Node('E', right=Node('G', Node('F'))))
    print('前序遍历:')
    root.preTraverse()
    print('\n中序遍历:')
    root.midTraverse()
    print('\n后序遍历:')
    root.afterTraverse()

二叉树层次遍历(BFS,DFS)

# 先造出来一棵简单的二叉树结构供使用
class Tree:
    def __init__(self, list_of_three):
        # list_of_three [1,2,3]  根左右
        # print("依次输入树的根、左节点、右节点")
        # .node其实是当前节点的值
        # 面向对象思想还是挺有用的
        if list_of_three[0] != 0:
            self.node = list_of_three[0]
        else:
            self.node = "none"
        if list_of_three[1] != 0:
            self.left = list_of_three[1]
        else:
            self.left = "none"
        if list_of_three[2] != 0:
            self.right = list_of_three[2]
        else:
            self.right = "none"


# 进行广度优先遍历BFS
def BFS(root_node):
    # pop(0)和append()是队列
    q = []
    q.append(root_node)
    while len(q) != 0:
        temp = q.pop(0)
        print(temp.node)
        if temp.left != "none":
            q.append(temp.left)
        if temp.right != "none":
            q.append(temp.right)


# 使用递归方式实现DFS
def DFS_recursion(root_node):
    print(root_node.node)
    if root_node == "none":
        return
    if root_node.left != "none":
        DFS_recursion(root_node.left)
    if root_node.right != "none":
        DFS_recursion(root_node.right)

# 使用栈来实现DFS
def DFS_stack(root_node):
    # pop()和append()是栈,pop()就差个0与队列相比
    s = []
    if root_node == "none":
        return
    s.append(root_node)
    while len(s) != 0:
        temp = s.pop()
        print(temp.node)
        if temp.right != "none":
            s.append(temp.right)
        if temp.left != "none":
            s.append(temp.left)


def main():
    # 自定义搭建了一棵二叉树
    node = "root"
    n = [i for i in range(12)]
    for i in range(12):
        n[i] = Tree([i, 0, 0])
    n[5] = Tree([5, n[10], n[11]])
    n[4] = Tree([4, n[8], n[9]])
    n[3] = Tree([3, n[6], n[7]])
    n[2] = Tree([2, n[4], n[5]])
    n[1] = Tree([1, n[2], n[3]])
    # 变量的覆盖作用,导致之前的未被更新,解释性语言,所以赋值需要从后往前
    print("--------------------------------------------------------------")
    print("基于递归的深度优先遍历:")
    DFS_recursion(n[1])
    print("--------------------------------------------------------------")
    print("基于栈的深度优先遍历:")
    DFS_stack(n[1])
    print("--------------------------------------------------------------")
    print("广度优先遍历:")
    BFS(n[1])
    print("--------------------------------------------------------------")


if __name__ == "__main__":
    main()

判断两颗树是否相同

def isSample(p,q):
   if p == None and q == None:
       return True
   elif p and q:
       return p.val == q.val and isSample(p.left, q.left) and isSample(p.right, q.right)
   else:
       return False

LeetCode98判断是否为合法的二分搜索树BST

def isValidBST(self, root, floor=float('-inf'), ceiling=float('inf')):
    if not root:
        return True
    if root.val < floor or root.val > ceiling:
        return False
    return self.isValidBST(root.left, floor, root.val) and self.isValidBST(root.right, root.val, ceiling)

LeetCode236. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

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

示例 1:
在这里插入图片描述

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3

解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

示例 2:
在这里插入图片描述

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5

解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

解题思路:

祖先的定义: 若节点 p 在节点 root 的左(右)子树中,或 p=root ,则称root 是 p的祖先。

最近公共祖先的定义: 设节点 root 为节点 p,q 的某公共祖先,若其左子节点 root.left和右子节点 root.right 都不是p,q 的公共祖先,则称root 是 “最近的公共祖先” 。

Picture1.png

根据以上定义,若root 是 p,q 的 最近公共祖先 ,则只可能为以下情况之一:

p 和 q 在root 的子树中,且分列 root 的 异侧(即分别在左、右子树中);
p=root ,且 q 在root 的左或右子树中;
q=root ,且 p 在root 的左或右子树中;

Picture2.png

考虑通过递归对二叉树进行先序遍历,当遇到节点 ppp 或 qqq 时返回。从底至顶回溯,当节点 p,qp, qp,q 在节点 rootrootroot 的异侧时,节点 rootrootroot 即为最近公共祖先,则向上返回 rootrootroot 。
递归解析:

终止条件:
    当越过叶节点,则直接返回 null ;
    当 root 等于p,q ,则直接返回root ;
递推工作:
    开启递归左子节点,返回值记为left ;
    开启递归右子节点,返回值记为 right ;
返回值: 根据 left 和 right ,可展开为四种情况;
    当 left 和right 同时为空 :说明root 的左 / 右子树中都不包含p,q ,返回 null ;
    当 left 和 right 同时不为空 :说明 p,q 分列在root 的 异侧 (分别在 左 / 右子树),因此root 为最近公共祖先,返回root ;
    当left 为空 ,right 不为空 :p,q 都不在root 的左子树中,直接返回 right 。具体可分为两种情况:
       p,q 其中一个在 root 的 右子树 中,此时 right 指向 p(假设为 p );
       p,q 两节点都在 root 的 右子树 中,此时的 right 指向 最近公共祖先节点 ;
    当left 不为空 ,right 为空 :与情况 3. 同理;
class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if not root or root == p or root == q: return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if not left and not right: return # 1.
        if not left: return right # 3.
        if not right: return left # 4.
        return root # 2. if left and right:

LeetCode111. 二叉树的最小深度

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
# 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 minDepth(self, root: TreeNode) -> int:
        # 二叉树为空,最小高度为 0
        if root == None:
            return 0
        # 只有根节点,最小高度为 1
        if root.left == None and root.right == None:
            return 1
        # 左子树最小值和右子树最小值
        leftMindepth = self.minDepth(root.left)
        rightMindepth = self.minDepth(root.right)

        # 如果节点的左子树不为空,右子树为空
        if root.left != None and root.right == None:
            return leftMindepth + 1
        # 如果节点的右子树不为空,左子树为空
        if root.left == None and root.right != None:
            return rightMindepth + 1
        # 左右子树都不为空
        return min(leftMindepth, rightMindepth) + 1

LeetCode104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

# python3 递归
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root:return 0
        return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1

DFS

class Solution(object):
    def maxDepth(self, root):
        if not root:
            return 0
        paths= []
        count = 1
        stack = [(root,str(root.val),count)]
        res = 0
        while stack:
            node,path,cou = stack.pop()
            if not node.left and not node.right:
                res = max(cou,res)
            print(cou,path)
            if node.left:
                stack.append((node.left,path + '->' + str(node.left.val),cou + 1))
            if node.right:
                stack.append((node.right,path + '->' + str(node.right.val),cou + 1))
        return res

BFS

class Solution(object):
    def maxDepth(self, root):
        if not root:
            return 0
        queue = [root]
        height = 0
        while queue:
            currentSize = len(queue)
            for i in range(currentSize):
                node = queue.pop(0)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            height += 1
        return height

LeetCode98. 验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例 1:
在这里插入图片描述

输入:root = [2,1,3]
输出:true

示例 2:
在这里插入图片描述

输入:root = [5,1,4,null,null,3,6]
输出:false

解释:根节点的值是 5 ,但是右子节点的值是 4 。

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

LeetCode226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:
在这里插入图片描述

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:
在这里插入图片描述

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]
# 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 invertTree(self, root: TreeNode) -> TreeNode:
        
        def traverse(root):
            if root is None:
                return None
            root.left, root.right = root.right, root.left
            self.invertTree(root.left)
            self.invertTree(root.right)

        traverse(root)
        return root

LeetCode230. 二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

示例 1:
在这里插入图片描述

输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:
在这里插入图片描述

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def __init__(self):
        self.rank = 0
        self.res = 0
    def kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """
        self.traverse(root,k)
        return self.res
    def traverse(self, root, k):
        if not root: return;
        self.traverse(root.left, k) 
        self.rank += 1 
        # 找出第k小的元素
        if self.rank == k:
            self.res = root.val
        self.traverse(root.right, k)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值