Leetcode-树

98. 验证二叉搜索树 https://leetcode-cn.com/problems/validate-binary-search-tree/

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

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

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

解:

中序遍历二叉排序树,判断得到的数组是否是升序。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        inorder = self.inorder(root)
        return inorder == sorted(set(inorder))  # 这里要注意判重
        
    def inorder(self, root):
        if root is None:
            return []
        return self.inorder(root.left) + [root.val] + self.inorder(root.right)

  

但是这个效率是相对较低的,想办法改进一下,不用完整保留中序遍历的结果,只需要比较中序遍历时当前节点和前驱节点即可

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        self.prev = None
        return self.helper(root)
    
    def helper(self, root):
        if root is None:
            return True
        if not self.helper(root.left):  # 如果左子树不是二叉搜索树,那root也不是
            return False
        if self.prev and self.prev.val >= root.val: # 如果左子树是二叉搜索树,比较root和其前驱节点值,如果前驱大,root不是二叉搜索树
            return False
        self.prev = root  # 如果满足root比前驱大,下面去检查右子树,在此之前要先把前驱节点更新为root
        return self.helper(root.right)

  

直接递归来判断

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        if root is None:
            return True
        if root.left is None and root.right is None:
            return True
   
        flag = True
        if root.left: 
            if not self.isValidBST(root.left):
                flag = False
            # 左子树的最大,一直向右即可
            l = root.left
            while l.right:
                l = l.right
            if root.val <= l.val:
                flag = False
                
        if root.right:    
            if not self.isValidBST(root.right):
                flag = False
            # 右子树的最小,一直向左即可
            r = root.right
            while r.left:
                r = r.left
            if root.val >= r.val:
                flag = False
        return flag

  

这个递归写的也是比较冗余的,有很多重复搜索。再简化一下,每次都把节点和其上下界比较(如果有的话)。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        return self.isValid(root)
    
    def isValid(self, root, lower=float('-inf'), upper=float('inf')):
        if root is None:
            return True
        val = root.val
        if lower is not None and val <= lower:
            return False
        if upper is not None and val >= upper:
            return False
        if not self.isValid(root.left, lower, val):
            return False
        if not self.isValid(root.right, val, upper):
            return False
        return True

  

235. 二叉搜索树的最近公共祖先 https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

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

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

说明:

所有节点的值都是唯一的。

p、q 为不同节点且均存在于给定的二叉搜索树中。

解:

迭代,从根节点往下,如果根节点比两个节点都大,说明两个节点在根节点的左子树中;如果根节点比两个节点都小,说明两个节点在根节点的右子树中。更新根节点即可。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return None
        if root.left is None and root.right is None:
            return root
        ans = root
        while ans:
            if ans.val < p.val and ans.val < q.val:
                ans = ans.right
            elif ans.val > p.val and ans.val > q.val:
                ans = ans.left
            else:
                return ans

  

递归实现,空间复杂度O(N)。这题其实没必要用递归

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

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.right, p, q)  # p、q比root都大,需要去root右子树查找
        if root.val > p.val and root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)
     return root

  

236.二叉树的最近公共祖先 https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

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

解:

递归,从根节点开始向下,如果root就是p或者q,那么公共祖先就是root,否则的话分别去左右子树查找p和q,如果p、q都在左子树,递归的去左子树向下查找;如果p、q都在右子树,递归的去右子树查找;如果p、q各在一边,那么root

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root is None or root is q or root is p:
            return root
        left = self.lowestCommonAncestor(root.left, p, q)  # 分别去左右子树查找p和q
        right = self.lowestCommonAncestor(root.right, p, q)
        if left is None:  # 如果p、q都不在左子树,返回右子树的查找结果
            return right
        elif right is None:  # 如果p、q都不在右子树,返回左子树的查找结果
            return left
        return root   # 如果p和q各在左右一边,公共祖先就是当前root

  

使用父指针迭代,找出 p 和 q 的各自到根节点的路径。如果每个节点都有父指针,可以从 p 和 q 返回以获取它们的祖先。在这个遍历过程中,得到的第一个公共节点是 LCA 节点。可以在遍历树时将父指针保存在字典中。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        parent = {root: None}
        stack = [root]
        
        # 只要没有把p、q都找到,就继续向下遍历树,继续找
        while p not in parent or q not in parent:
            node = stack.pop()
            
            if node.left:
                parent[node.left] = node
                stack.append(node.left)
                
            if node.right:
                parent[node.right] = node
                stack.append(node.right)
                
        ancestors = set()  # 按父指针遍历p的祖先
        while p:
            ancestors.add(p)
            p = parent[p]
        
        while q not in ancestors:  # 找p、q公共的祖先
            q = parent[q]
        return q

  

原文地址:https://www.cnblogs.com/chaojunwang-ml/p/11355359.html