zoukankan      html  css  js  c++  java
  • 算法树

    一、二叉查找树-平衡树

    1、前置知识:二叉树的深度

    # 节点定义如下
    # Definition for a binary tree node.
    class TreeNode:
        def __init__(self, x):
            self.val = x
            self.left = None
            self.right = None
    n3 = TreeNode(3)
    n9 = TreeNode(9)
    n20 = TreeNode(20)
    n15 = TreeNode(15)
    n7 = TreeNode(7)
    
    n3.left = n9
    n3.right = n20
    n20.left = n15
    n20.right = n7
    n3 = TreeNode(3)
    n9 = TreeNode(9)
    n20 = TreeNode(20)
    n15 = TreeNode(15)
    n7 = TreeNode(7)
    
    n3.left = n9
    n3.right = n20
    n20.left = n15
    n20.right = n7
    Solution().maxDepth(n3)
    # 方法一:每到一个节点,深度就+1
    class Solution:
        def maxDepth(self, root: TreeNode) -> int:
            return self.get_dep(root, 1)
    
        def get_dep(self, node, depth):
            if not node:
                return depth - 1
            return max(self.get_dep(node.left,depth+1),self.get_dep(node.right,depth+1))
    
    
    # 方法二:
    class Solution:
        def maxDepth(self, root: TreeNode) -> int:
            if root is None:
                return 0
            else:
                left_depth = self.maxDepth(root.left)
                right_depth = self.maxDepth(root.right)
            return max(left_depth,right_depth)+1
    算法解析:
    终止条件: 当 root​ 为空,说明已越过叶节点,因此返回 深度 0 。
    递推工作: 本质上是对树做后序遍历,从叶子节点一层层向上加
    计算节点 root​ 的 左子树的深度 ,即调用 maxDepth(root.left);
    计算节点 root​ 的 右子树的深度 ,即调用 maxDepth(root.right);
    返回值: 返回 此树的深度 ,即 max(maxDepth(root.left), maxDepth(root.right)) + 1。
    方法二解析

    2、判断这个二叉树是否为平衡二叉树

    # 方法一
    class Solution:
        def isBalanced(self, root: TreeNode) -> bool:
            if not root:
                # 空树也是平衡树
                return True
            left_height = self.get_dep(root.left, 1)
            right_height = self.get_dep(root.right, 1)
            if abs(left_height-right_height) > 1:
                return False
            else:
                return self.isBalanced(root.left) and self.isBalanced(root.right)
    
        def get_dep(self, node, depth):
            if not node:
                return depth - 1
            return max(self.get_dep(node.left,depth+1),self.get_dep(node.right,depth+1))
    
    
    # 方法二
    class Solution:
        def isBalanced(self, root: TreeNode) -> bool:
            if not root:
                return True
    
            left_height = self.depth(root.left)
            right_height = self.depth(root.right)
            if abs(left_height - right_height) > 1:
                return False
            else:
                return self.isBalanced(root.left) and self.isBalanced(root.right)
    
        def depth(self, root):
            if not root: 
                return 0
    
            return max(self.depth(root.left), self.depth(root.right)) + 1

    二、树的前中后序遍历

    作者:z1m
    链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/

    来源:力扣(LeetCode)

    # 前序遍历
    # 递归
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def preorderTraversal(self, root: TreeNode) -> List[int]:
            res = []
            def tree(node):
                if not node:
                    return
                res.append(node.val)
                tree(node.left)
                tree(node.right)
            tree(root)
            return res
    
    
    # 迭代
    class Solution:
        """
        它先将根节点 cur 和所有的左孩子入栈并加入结果中,直至 cur 为空,用一个 while 循环实现:
        然后,每弹出一个栈顶元素 tmp,就到达它的右孩子,再将这个节点当作 cur 重新按上面的步骤来一遍,直至栈为空。这里又需要一个 while 循环。
        """
        def preorderTraversal(self, root: TreeNode) -> List[int]:
            if not root:
                return []
            
            cur, stack, res = root, [], []
            while cur or stack:
                while cur:  # 根节点和左孩子入栈
                    res.append(cur.val)
                    stack.append(cur)
                    cur = cur.left
                tmp = stack.pop()  # 每弹出一个元素,就到达右孩子
                cur = tmp.right
            return res
    
    
    
    # 中序遍历
    # 递归
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def inorderTraversal(self, root: TreeNode) -> List[int]:
            res = []
            def tree(node):
                if not node:
                    return
                tree(node.left)
                res.append(node.val)
                tree(node.right)
            tree(root)
            return res
    
    
    
    # 迭代
    class Solution:
        """
        和前序遍历的代码完全相同,只是在出栈的时候才将节点 tmp 的值加入到结果中。
        """
        def inorderTraversal(self, root: TreeNode) -> List[int]:
            if not root:
                return []
            
            cur, stack, res = root, [], []
            while cur or stack:
                while cur:  # 根节点和左孩子入栈
                    stack.append(cur)
                    cur = cur.left
                tmp = stack.pop()
                res.append(cur.val)  # 出栈再加入结果
                cur = tmp.right
            return res
    
    
    # 后续遍历
    # 递归
    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            res = []
            def tree(node):
                if not node:
                    return
                tree(node.left)
                tree(node.right)
                res.append(node.val)
            tree(root)
            return res
    
    
    
    # 迭代
    class Solution:
        """
        继续按照上面的思想,这次我们反着思考,节点 cur 先到达最右端的叶子节点并将路径上的节点入栈;
        然后每次从栈中弹出一个元素后,cur 到达它的左孩子,并将左孩子看作 cur 继续执行上面的步骤。
        最后将结果反向输出即可。参考代码如下:
        """
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            if not root:
                return []
            
            cur, stack, res = root, [], []
            while cur or stack:
                while cur:  # 先达最右端
                    res.append(cur.val)
                    stack.append(cur)
                    cur = cur.right
                tmp = stack.pop()
                cur = tmp.left
            return res[::-1]

    三、广度搜索算法

    1、102. 二叉树的层序遍历

    题目连接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

    作者:JonnyHuang
    链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/python3-er-cha-shu-ceng-xu-bian-li-by-jo-nlx3/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    BFS(Breadth First Search)

    JonnyHuang作者的思路

    # 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 levelOrder(self, root: TreeNode) -> List[List[int]]:
            """
            步骤:
                1.遍历当前层级,把当前层的所有节点的值存到结果列表中
                2.再次遍历当前层级,把当前层的所有节点的下一层级(左右节点)添加到遍历列表中
                3.重复1、2步
            """
            if not root:
                return []
    
            queue = [root]  # 当前层级的所有节点,默认从根节点开始
            res = []  # 最终结果列表
            while queue:
                res.append([cur_node.val for cur_node in queue])  # 步骤1
                level = []  # 存储下一层级的所有节点
                for node in queue:
                    # 步骤2
                    if node.left:
                        level.append(node.left)
                    if node.right:
                        level.append(node.right)
                queue = level
            return res

    官方写法:

    # Definition for a binary tree node.
    # class TreeNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution:
        def levelOrder(self, root: TreeNode) -> List[List[int]]:
            if not root:
                return []
            
            res = []
            stack = [root, ]  # 进行遍历的节点顺序
            while stack:
                level = []  # 每层的节点都存在一起
                n = len(stack)  # 每层需要处理的节点数
                for _ in range(n):
                    node = stack.pop(0)  # 当前处理的节点
                    level.append(node.val)
                    if node.left:
                        stack.append(node.left)
                    if node.right:
                        stack.append(node.right)
                if level:
                    res.append(level)
            return res

    2、107. 二叉树的层序遍历 II

    https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/

    给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

    # 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 levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
            """
            步骤:
                1.遍历当前层级,把当前层的所有节点的值存到结果列表中
                2.再次遍历当前层级,把当前层的所有节点的下一层级(左右节点)添加到遍历列表中
                3.重复1、2步
                4.返回值可使用切片倒叙输出
            """
            if not root:
                return []
    
            queue = [root]  # 当前层级的所有节点,默认从根节点开始
            res = []  # 最终结果列表
            while queue:
                res.append([cur_node.val for cur_node in queue])  # 步骤1
                level = []  # 存储下一层级的所有节点
                for node in queue:
                    # 步骤2
                    if node.left:
                        level.append(node.left)
                    if node.right:
                        level.append(node.right)
                queue = level
            return res[::-1]

    3、199. 二叉树的右视图

    https://leetcode-cn.com/problems/binary-tree-right-side-view/

    给定一个二叉树的 根节点 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 rightSideView(self, root: TreeNode) -> List[int]:
            """
            步骤:
                1.遍历当前层级,右视图即每层最右边的值,即只需要对每一层的列表的最后一个元素入结果列表就可以了
                2.再次遍历当前层级,把当前层的所有节点的下一层级(左右节点)添加到遍历列表中
                3.重复1、2步
            """
            if not root:
                return []
    
            queue = [root]  # 当前层级的所有节点,默认从根节点开始
            res = []  # 最终结果列表
            while queue:
                res.append([cur_node.val for cur_node in queue][-1])  # 步骤1
                level = []  # 存储下一层级的所有节点
                for node in queue:
                    # 步骤2
                    if node.left:
                        level.append(node.left)
                    if node.right:
                        level.append(node.right)
                queue = level
            return res

    四、深度搜索算法

    1、102. 二叉树的层序遍历

    https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

    上面102题,我们也可以使用深度搜索算法

    DFS(Depth First Search)不是按照层次遍历的。为了让递归的过程中同一层的节点放到同一个列表中,在递归时要记录每个节点的深度 level。递归到新节点要把该节点放入 level 对应列表的末尾。

    作者:edelweisskoko
    链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/102-er-cha-shu-de-ceng-xu-bian-li-die-da-bg9v/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    class Solution:
        def levelOrder(self, root: TreeNode) -> List[List[int]]:
            """
            1.因为每层的节点值要分开记录,所以递归的参数除了节点node以外还需要当前层数level
            2.如果节点已为空,return,结束当前递归分支即可
            3.如果res的长度已经和当前层数level相等,说明res需要多加个位置了,因为level是res数组的索引,索引是一定比长度要小的,如果相等说明数组长度不够长了,得扩容
            4.把当前节点加到对应层的数组中去res[level].append(node.val)
            5.继续依次遍历左右字节点,层数level + 1
            6.返回res
            """
            res = []
    
            def dfs(node, level):
                if not node:
                    return
                if len(res) == level:
                    res.append([])
                res[level].append(node.val)
                dfs(node.left, level + 1)
                dfs(node.right, level + 1)
    
            dfs(root, 0)
            return res

    2、207. 课程表

    https://leetcode-cn.com/problems/course-schedule/
    作者:jyd
    链接:https://leetcode-cn.com/problems/course-schedule/solution/course-schedule-tuo-bu-pai-xu-bfsdfsliang-chong-fa/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    class Solution:
        def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
            """
            三个标志位对应的状态
            i == 0 : 干净的,未被 DFS 访问
            i == -1:其他节点启动的 DFS 访问过了,路径没问题,不需要再访问了
            i == 1  :本节点启动的 DFS 访问过了,一旦遇到了也说明有环了
            """
    
            def dfs(i, adjacency, flags):
                if flags[i] == -1:
                    return True
                if flags[i] == 1:
                    return False
                flags[i] = 1
                for j in adjacency[i]:
                    if not dfs(j, adjacency, flags):
                        return False
                flags[i] = -1
                return True
    
            # 初始化每个课程的依赖(列表)
            adjacency = [[] for _ in range(numCourses)]
            # 每个课程的标志位
            flags = [0 for _ in range(numCourses)]
            # 填充完成每个课程的依赖
            for cur, pre in prerequisites:
                adjacency[cur].append(pre)
            # 开始DFS去判断
            for i in range(numCourses):
                if not dfs(i, adjacency, flags):
                    return False
            return True
  • 相关阅读:
    Autotools使用流程【转】
    Linux下GCC生成和使用静态库和动态库【转】
    Linux驱动模块的Makefile分析【转】
    GNU C 中零长度的数组【转】
    Linux设备驱动中的IO模型---阻塞和非阻塞IO【转】
    程序(进程)内存分布解析【转】
    【转】用户空间使用i2c_dev--不错
    开源课堂网址
    【转】用Device tree overlay掌控Beaglebone Black的硬件资源
    【转】Device Tree(三):代码分析
  • 原文地址:https://www.cnblogs.com/Zzbj/p/15562013.html
Copyright © 2011-2022 走看看