LeetCode--相关二叉树的例题与理解

1、相同的树
给定两个二叉树,编写一个函数来检验它们是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:

输入:      
           1         1
          / \       / \
         2   3     2   3
        [1,2,3],   [1,2,3]
输出: true

示例 2:

输入:      1         1
          /           \
         2             2

        [1,2],     [1,null,2]
输出: false

示例 3:

输入:  
           1         1
          / \       / \
         2   1     1   2

        [1,2,1],   [1,1,2]
输出: false

解题思路:广度遍历这棵树,比较这两个树的列表是否相同,但是需要注意的是:从左往右,也就是没有左子节点时用None表示。

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

class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        # 广度遍历
        def tree2list(t_head):
            if t_head is None:
                return None
            else:
                node_li = [t_head]
                val_li = [t_head.val]
                while node_li:
                    cur_node = node_li.pop(0)
                    if cur_node.left is None:
                        val_li.append(None)
                    else:
                        node_li.append(cur_node.left)
                        val_li.append(cur_node.left.val)
                    if cur_node.right is not None:
                        node_li.append(cur_node.right)
                        val_li.append(cur_node.right.val)
                return val_li
        p_li = tree2list(p)
        q_li = tree2list(q)
        return p_li==q_li

思路2:递归,深度遍历,对比相同节点位置的值是不是相同
1、 如果两棵树都是None,返回True
2、 非空的两棵树,使用递归,递归的退出条件相同位置的节点的值不同

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

class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """        
        if not p and not q:
            return True
        elif p is not None and q is not None:
            if p.val == q.val:
                return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
            else:
                return False
        else:
            return None

2、对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

   1
   / \
  2   2
   \   \
   3    3

说明:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。

解题思路:递归,左右两棵子树,相同位置的根节点的值相同,左子树的左子树与右子树的右子树是镜像,左子树的右子树与右子树的左子树是镜像关系,那么,这两棵子树就是镜像关系:

left.val == right.val and self.isMirror(left.right, right.left) and self.isMirror(left.left, right.right)

递归的退出条件:深度遍历到叶子节点时

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

class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        return self.isMirror(root, root)
    def isMirror(self, left, right):
        if left is None and right is None:
            return True
        if left is None or right is None:
            return False
        return left.val == right.val and self.isMirror(left.right, right.left) and self.isMirror(left.left, right.right)

3、 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。
解题思路:
1、 广度遍历:列表里的元素:(当前节点的深度,节点对象),当(1,3)节点出栈的时候,比较当前的深度与初始设置饿最大深度的大小,然后3接连的左右节点进栈,一次类推,找出最后叶子节点的深度

(1,3)
(2,9)
(2,20)
(3,15)
(3,7)
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0
        else:
            q = [(1, root)]
            max_depth = 0
            while q:
                depth, cur_node = q.pop(0)
                if cur_node is not None:
                    max_depth = max(depth, max_depth)
                    q.append((depth + 1, cur_node.left))
                    q.append((depth + 1, cur_node.right))
            return max_depth

2、 递归,深度遍历,先遍历左子树,然后右子树,返回左右子树中深度最大的那一个
递归退出的条件:如果子树的根节点为None,退出,说明已经到叶子节点了

    3         3
   / \
  9  20       2
    /  \
   15   7     1
  /  \/  \    
   (None)     0

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

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None: 
            return 0 
        else: 
            left_height = self.maxDepth(root.left) 
            right_height = self.maxDepth(root.right) 
            return max(left_height, right_height) + 1

4、二叉树的层次遍历
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如:
给定二叉树 [3,9,20,null,null,15,7],

    3           1层
   / \
  9  20         2层
    /  \
   15   7       3层

返回其自底向上的层次遍历为:

[
  [15,7],
  [9,20],
  [3]
]

解题思路:
1、广度遍历,但有所区别,这里并不是取出一个节点后把它的左右节点放到队列中,而是在这个队列里只存在一个层次的所有节点,然后遍历一下这个队列,获取里面所有元素的值放到一个列表里。所以这里实现的时候使用了一个临时队列,在遍历队列中一个层次的所有节点的同时,把这个层次里所有节点的左右子节点(也就是下一层次)放到这个临时队列中,然后让真正的队列引用这个临时队列。最后把所有层次的数值列表按顺序插入最后返回的列表。

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

class Solution(object):
    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        
        if root is None:
            return None
        else:
            query = [root]
            res = []
           
            while query:
                each_row = []
                temp = []
                for i in query:
                    each_row.append(i.val)
                    if i.left is not None:
                        temp.append(i.left)
                    if i.right is not None:
                        temp.append(i.right)
                query = temp
                res.insert(0, each_row)
            return res

2、递归,深度遍历(线序),保存根节点后遍历左子树,直到叶子节点后遍历右子树

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

class Solution(object):
    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        def helper(node, depth, res):
            """
            利用前序遍历的思想
            """
            if not node:
                return   递归退出的条件
            # 超出递归的长度表明是新的一层,则新添加数组
            if depth < 0 and abs(depth) > len(res):
                res.insert(0, [])
            # 可以理解成每个node都能对应到树的depth
            res[depth].append(node.val)    递归过程中的业务处理
            if node.left:
                helper(node.left, depth-1, res)
            if node.right:
                helper(node.right, depth-1, res)    递归

        result = []
        helper(root, -1, result)
        return result

5、将有序数组转化成二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:

给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5
                                  

                                              [有序列表]
                                                 / \
解题思路:递归,将一个有序数组分成:        [左子树]、[根节点]、[右子树]
                                      / \                 / \
                       [左子树]、[根节点]、[右子树]     [左子树]、[根节点]、[右子树]
                        /\                  /\         /\               /\
                         …                  …                   …                   …  

1、 退出递归的条件
2、 执行递归前的业务处理
3、 递归(调用函数本身)

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

class Solution(object):
    def sortedArrayToBST(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        if not nums:
            return None     退出递归的条件

        mid = len(nums) // 2
        t = TreeNode(nums[mid])
        nums1 = nums[:mid]
        nums2 = nums[mid+1:]          业务处理

        t.left = self.sortedArrayToBST(nums1)
        t.right = self.sortedArrayToBST(nums2)       递归

        return t

6、平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]

       1
      / \
     2   2
    / \
   3   3
  / \
 4   4

返回 false 。
解题思路:递归,包括两个递归函数,一个是判断左右子树是否是平衡二叉树,另一个是求解每棵子树的高度
1、 判断左右子树是否为平衡二叉树的递归函数:

  • 1、 退出递归的条件
  • 2、 在执行递归函数之前的业务逻辑处理(这里是判断左、右子树的高度差的绝对值是不是<=1)
  • 3、 递归

2、 返回树的高度的递归函数:

  • 1、 退出递归函数的条件
  • 2、 业务逻辑处理
  • 3、 递归

当然业务逻辑处理可有可无,可以在递归前、递归中、递归后

# 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 isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if not root:
            return True
        
        if abs(self.height(root.left)-self.height(root.right))>1:
            return False
        
        return self.isBalanced(root.left) and self.isBalanced(root.right)
        
    def height(self,root):
        if not root:
            return 0
        
        left = self.height(root.left) + 1
        right = self.height(root.right) + 1
        return max(right, left)

7、二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],

   3
   / \
  9  20
    /  \
   15   7

返回它的最小深度 2.
解题思路:递归,使用深度搜索,与上例的最大深度有点类似,但是不能只是简单的把return max(right, left)改成return min(right, left),这里有一种特殊的情况:

    3
   / 
  9 
 这种情况下的树的最小深度是2,不是1,所以在根节点的左右子节点都存在的情况下,
 return min(right, left)这种形式完全可以,当只有左节点或右节点时,返回的是包含
 左(右)节点的深度。

1、 递归退出的条件
2、 业务逻辑处理

  • 2.1、如果左右节点都存在:
  • 2.2、递归1
  • 2.3、如果只存在左节点:
  • 2.4、递归2
  • 2.5、如果只存在右节点:
  • 2.6、递归3
    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def minDepth(self, root):
            """
            :type root: TreeNode
            :rtype: int
            """
            if not root:
                return 0
    
            elif root.left and root.right:
                left = self.minDepth(root.left) + 1
                right = self.minDepth(root.right) + 1
                return min(left, right)
    
            elif root.left:
                left = self.minDepth(root.left) + 1
                return left
    
            elif root.right:
                right = self.minDepth(root.right) + 1
                return right
    
            else:
                return 1

思路二:广度搜索,当遍历到叶子节点时,返回当前的深度,然后比较出最小深度大小

(1,3) 根节点
(2,9) 叶子节点(深度为2)
(2,9) 叶子节点(深度为2)
(2,20)
(3,15) 叶子节点(深度为3)
(3.7) 叶子节点(深度为3)
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0
        queue = [(1, root)]
        min_depth = float('Inf')  # 正无穷
        while queue:
            depth, t = queue.pop()
            if not t.left and not t.right:
                min_depth = min(min_depth, depth)
                
            if t.left:
                queue.append((depth + 1, t.left))
            if t.right:
                queue.append((depth + 1, t.right))
                
        return min_depth

8、路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,

      5
     / \
    4   8
   /   / \
  11  13  4
 /  \      \
7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
解题思路:深度遍历,一直到叶子节点,判断和是否为sum值

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

class Solution(object):
    def hasPathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: bool
        """
        if not root:
            return False    是否为空树

        if root.left is None and root.right is None:    叶子节点的判断
            return sum - root.val == 0

        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)

猜你喜欢

转载自blog.csdn.net/weixin_41599977/article/details/89196958