代码-树系列(更新中)

“抱佛脚”系列(代码部分); 所有代码均基于 Python3;
记号 LC{xx} 表示 Leetcode 第 xx 题,例如 LC20 表示 Leetcode 第 20题。

题目索引

  • “树”的定义
  • 基础:树的遍历
    • 中序遍历(LC94)
    • 前序遍历(LC144)
    • 层序遍历 (LC02)(广度优先,BFS)
  • 高频题目
    • LC108 - 将有序数组转化为二叉搜索树
    • LC98 - 验证二叉搜索树
    • LC105 - 从前序遍历和中序遍历构造二叉树
    • 腾讯面试 - 二叉树节点集合的最大分数
    • LC235 - 二叉搜索树的最近公共祖先
    • LC236 - 二叉树的最近公共祖先

“树”的定义

# 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

基础:树的遍历

  • 前序遍历:根-左-右
  • 中序遍历:左-根-右
  • 后序遍历:右-左-根

中序遍历(LC94)

中序遍历的顺序:左-根-右 (left - root - right)

# 给定一个二叉树的根节点 root ,返回它的 中序 遍历。
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if root is None:
            return []
        return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)

前序遍历(LC144)

# 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        if root is None:
            return []
        return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)

层序遍历 (LC02)(广度优先,BFS)

  • 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)
    代码-树系列(更新中)_第1张图片
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if root is None:
            return []
        res = []
        nodes_next = [root]
        while len(nodes_next):
            res.append([nd.val for nd in nodes_next])
            tmp = []
            for node in nodes_next:
                if node.left: tmp.append(node.left)
                if node.right: tmp.append(node.right)
            nodes_next = tmp
        return res

高频题目

LC108 - 将有序数组转化为二叉搜索树

链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree

  • 二分,找到数组终点
  • 递归构建
class Solution: 
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode: 
        if len(nums) <= 0: 
        	return 
        elif len(nums) <= 1: 
            return TreeNode(val = nums[0]) 
        mid = len(nums) // 2 
        root = TreeNode( 
        		val = nums[mid], 
                left = self.sortedArrayToBST(nums[: mid]), 
                right = self.sortedArrayToBST(nums[mid + 1: ])
            ) 
        return root

LC98 - 验证二叉搜索树

链接:https://leetcode-cn.com/problems/validate-binary-search-tree

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

一个二叉搜索树具有如下特征:

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

⚠️要点

  1. 方法一:中序遍历二叉搜索树得到的一定是一个有序数组(代码略)
  2. 方法二:递归,引入辅助函数(方便参数传递,如下)
class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        return self._is_valid(root)

    def _is_valid(self, root, vmin=-float("inf"), vmax=float("inf")):
        if root is None:
            return True
        if (root.val > vmin) and (root.val < vmax):
            return self._is_valid(root.left, vmin, root.val) and self._is_valid(root.right, root.val, vmax)
        return False

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

链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal

根据一棵树的前序遍历与中序遍历构造二叉树。
注意: 你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
代码-树系列(更新中)_第2张图片

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not len(preorder): return None
        root_val = preorder[0]
        root_loc = inorder.index(root_val) # 左数第一个匹配元素的下标
        return TreeNode(
            root_val, 
            left = self.buildTree(preorder[1: root_loc + 1], inorder[: root_loc]),
            right = self.buildTree(preorder[root_loc + 1: ], inorder[root_loc + 1: ])
        )

腾讯面试 - 二叉树节点集合的最大分数

(腾讯 面试题)

二叉树中每个节点有个分数,从中选择一些节点并返回它们的累加分数的最大值。规则:如果选择某个节点,就不能再选择它相邻的(子)节点。

⚠️要点

  • 递归求解 O(N), N 为树节点总数。
  • 每次返回两个值
    • 当前节点往下的子树最大分数(可能包含当前节点)
    • 不包含当前节点的子树最大分数
def maxScore(node: TreeNode):
	if node is None: return 0
	v11, v12 = maxScore(node.left)
	v21, v22 = maxScore(node.right)
	
	v_exclude_root = v11 + v21
	v_max = max(v12 + v22 + node.val, v_exclue_root)
	
	return v_max, v_exlude_root

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

链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree

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

最近公共祖先的定义为:

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

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

代码-树系列(更新中)_第3张图片

示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

# binary seaching tree
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val < root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)
        if p.val > root.val < q.val:
            return self.lowestCommonAncestor(root.right, p, q)
        return root

LC236 - 二叉树的最近公共祖先

与上一题不同的是,对于一般二叉树,节点的数值没有相对大小限制。

⚠️要点

分别递归搜索左/右子树,寻找p或q,会出现三种情况:

  1. 某棵子树不存在p也不存在q,那么公共节点一定在另一个子树上。
  2. 左/右子树均能找到p或q,当前root节点就是公共祖先。
  3. (终止条件)当前节点为None,或当前节点就是p或q中的一个,直接返回自己。
# general binary tree
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if (root is None) or (root is p) or (root is q):
            return root
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)
        if left and right:
            return root
        return right if left is None else left

你可能感兴趣的:(抱佛脚-面试算法工程师,leetcode,算法)