leetcode-树(一)

目录

104. 二叉树的最大深度

111. 二叉树的最小深度

226. 翻转二叉树

100. 相同的树

102. 二叉树的层序遍历

101. 对称二叉树

222. 完全二叉树的节点个数

110. 平衡二叉树

112. 路径总和

404. 左叶子之和


104. 二叉树的最大深度

https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。

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

    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。

题解

一:maxDepth返回以root为根的二叉树的最大深度。

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0

        return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1
class Solution(object):
    def maxDepth(self, root):
        if not root:
            return 0
        return self._max_depth(root)

    # return:以root为根的树的最大深度
    def _max_depth(self, root):
        if not root:
            return 0
        return max(self._max_depth(root.left), self._max_depth(root.right)) + 1

111. 二叉树的最小深度

https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明: 叶子节点是指没有子节点的节点。

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

    3
   / \
  9  20
    /  \
   15   7
返回它的最小深度  2.

题解

minDepth返回以root为根的最小深度,注意与104题的区别,这边要注意例如下面这种情况,树的最大深度是2,最小深度也是2,若依错误的写法,最小深度则是1,因为将1的右子树传入,则返回0,因此最终结果是1,但是我们发现1的左子树还是有值的,故不可这么做,那么若左子树为空,得看右子树;同理右子树为空得看左子树;都不为空,二者取最小:

[1,2]

    1
   / 
  2  

class Solution(object):
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0
        # if not root.left and not root.right:
        #     return 1
        elif not root.left:
            return self.minDepth(root.right) + 1
        elif not root.right:
            return self.minDepth(root.left) + 1
        else:
            return min(self.minDepth(root.left), self.minDepth(root.right)) + 1

下面这种解法是错误的

class Solution(object):
    def minDepth(self, root):
        if not root:
            return 0
        return min(self.minDepth(root.left), self.minDepth(root.right)) + 1

226. 翻转二叉树

https://leetcode-cn.com/problems/invert-binary-tree/

翻转一棵二叉树。

示例:

输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9
输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

题解

一:invertTree返回翻转后的二叉树的根(翻转以root为根的二叉树,并将新的二叉树的根返回 )。

class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if not root:
            return 
        new_left = self.invertTree(root.right)
        new_right = self.invertTree(root.left)
        root.left, root.right = new_left, new_right
        return root

100. 相同的树

https://leetcode-cn.com/problems/same-tree/

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

示例 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

题解

一:isSameTree返回以p和q为根的子树是否相同。

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

102. 二叉树的层序遍历

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

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

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

      3
     /  \
   9  20
       /  \
     15   7
返回其层次遍历结果:

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

题解

一:层序遍历。

from collections import deque
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        q, res = deque(), []
        q.append(root)
        while q:
            n = len(q)
            res.append([])
            for i in range(n):
                node = q.popleft()
                res[-1].append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
        return res

101. 对称二叉树

https://leetcode-cn.com/problems/symmetric-tree/

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [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
进阶:你可以运用递归和迭代两种方法解决这个问题吗?

题解

一:递归,以root为根的二叉树是否对称。转化成两个子树是否对称,即它们的两个根结点具有相同的值,每个树的右子树都与另一个树的左子树镜像对称。时间复杂度:O(n),因为我们遍历整个输入树一次,所以总的运行时间为 O(n),其中 n是树中结点的总数。

class Solution(object):
    # 以root为根的二叉树是否对称
    # 左子树的右孩子=右子树的左孩子
    # 左子树的左孩子=右子树的右孩子
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if not root:
            return True
        return self._isSymmetric(root.left, root.right)
    # 以left和right为根的二叉树是否对称
    def _isSymmetric(self, left, right):
        if not left and not right:
            return True 
        if (not left and right) or (not right and left) or (left.val != right.val):
            return False
        return (self._isSymmetric(left.right, right.left) and self._isSymmetric(left.left, right.right))

二:借鉴102题层序遍历的思路,每次取出一层之后看是否是镜像,当然下层中的None也要记录,不过下层为None,就没必要入队了,因为一旦上层形状给定,下层的形状(记录过None的)也唯一给定。

from collections import deque
class Solution(object):
    def isSymmetric(self, root):
        if not root or (not root.left and not root.right):
            return True
        if (not root.left and root.right) or (root.left and not root.right):
            return False
        q = deque()
        q.append(root)

        while q:
            n = len(q)
            rec = []
            for i in range(n):
                node = q.popleft()
                if node.left:
                    q.append(node.left)
                    rec.append(node.left.val)
                else:
                    rec.append(None)
                if node.right:
                    q.append(node.right)
                    rec.append(node.right.val)
                else:
                    rec.append(None)
            # print(rec)
            l, r = 0, len(rec) - 1
            while l < r:
                if rec[l] != rec[r]:
                    return False
                l += 1
                r -= 1
        return True

三:copy官方题解,https://leetcode-cn.com/problems/symmetric-tree/solution/dui-cheng-er-cha-shu-by-leetcode/,除了递归的方法外,我们也可以利用队列进行迭代。队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像。最初,队列中包含的是 root的左子树 以及 root的右子树。该算法的工作原理类似于 BFS,但存在一些关键差异。每次提取两个结点并比较它们的值。然后,将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

from collections import deque
class Solution(object):
    def isSymmetric(self, root):
        if not root or (not root.left and not root.right):
            return True
        if (not root.left and root.right) or (root.left and not root.right):
            return False
        q = deque()
        q.append(root.left)
        q.append(root.right)

        while q:
            l, r = q.popleft(), q.popleft()
            if not l and not r:
                continue
            if (not l and r) or (l and not r) or (l.val != r.val):
                return False
            q.append(l.left)
            q.append(r.right)
            q.append(l.right) 
            q.append(r.left)       
        return True

222. 完全二叉树的节点个数

给出一个完全二叉树,求出该树的节点个数。说明:完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例:

输入: 
    1
   / \
  2   3
 / \  /
4  5 6

输出: 6

题解

一:暴力求解,将每个节点都遍历一遍,O(n)的时间复杂度。

class Solution(object):
    def countNodes(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0
        return self.countNodes(root.left) + self.countNodes(root.right) + 1

二:借鉴官方题解https://leetcode-cn.com/problems/count-complete-tree-nodes/solution/wan-quan-er-cha-shu-de-jie-dian-ge-shu-by-leetcode/,求出树的最大深度d,因为完全二叉树,则非叶子 节点的个数2^{(d-1)}-1,然后关键是求出叶子节点的个数。

现在有两个问题:最后一层我们需要检查多少个节点?一次检查的最佳的时间性能是什么?
让我们从第一个问题开始思考。最后一层的叶子节点全部靠向左边,我们可以用二分搜索只检查 log(2^{(d-1)}) = d-1个叶子代替检查全部叶子。

让我们思考第二个问题,最后一层的叶子节点索引在[0,2^{(d - 1)} - 1]之间。如何检查第 idx 节点是否存在?让我们来用二分搜索来构造从根节点到 idx 的移动序列。如,idx = 4。idx 位于 0,1,2,3,4,5,6,7 的后半部分,因此第一步是向右移动;然后 idx 位于 4,5,6,7 的前半部分,因此第二部是向左移动;idx 位于 4,5 的前半部分,因此下一步是向左移动。一次检查的时间复杂度为 O(d)。我们需要 O(d)次检查,一次检查需要O(d),所以总的时间复杂度为O(d^2)

在这里插入图片描述

class Solution(object):
    # 深度 + 叶子节点的个数
    def countNodes(self, root):
        if not root:
            return 0
            
        d = self.depth(root)
        if d == 1:
            return 1

        non_leaf_nodes = 2 ** (d - 1) - 1

        l, r = 0, 2 ** (d - 1) - 1
        while l <= r:
            pivot = l + (r - l) // 2
            if self.exists(pivot , d, root):
                l = pivot + 1
            else:
                r = pivot - 1
        return non_leaf_nodes + l
 
    def depth(self, node):
        d = 1
        while node.left:
            d += 1
            node = node.left
        return d
    
    def exists(self, idx, d, node):
        l, r = 0, 2 ** (d - 1) - 1
        for _ in range(d - 1):
            pivot = l + (r - l) // 2
            if idx <= pivot:
                node = node.left
                r = pivot
            else:
                node = node.right
                l = pivot + 1
        return node is not None

110. 平衡二叉树

https://leetcode-cn.com/problems/balanced-binary-tree/

给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过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。若近乎平衡时间复杂度O(nlgn),对于每个深度为 d 的节点 p,_maxDepth被调用d(即lg(n))次。如果树是倾斜的,算法没有尽早结束,最终会达到 O(n^2)的复杂度。

class Solution(object):
    def isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if not root:
            return True
        if abs(self._maxDepth(root.left) - self._maxDepth(root.right)) > 1:
            return False
        return self.isBalanced(root.left) and self.isBalanced(root.right)
        
    def _maxDepth(self, node):
        if not node:
            return 0
        return max(self._maxDepth(node.left), self._maxDepth(node.right)) + 1

二:提前终止,时间复杂度为 O(N)。

class Solution(object):
    def isBalanced(self, root):
        if not root:
            return True
        return self._helper(root) != -1
        
    def _helper(self, node):
        if not node:
            return 0
        left_depth = self._helper(node.left)
        if left_depth == -1:
            return -1
        right_depth = self._helper(node.right)
        if right_depth == -1:
            return -1
        if abs(left_depth - right_depth) <= 1:
            return max(left_depth, right_depth) + 1
        return -1

112. 路径总和

https://leetcode-cn.com/problems/path-sum/

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

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

示例: 
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

题解

一:叶子节点判断,要保证叶子节点的合理性,需要先判断该节点是否为空

class Solution(object):
    def hasPathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: bool
        """
        if not root:
            return False
        if not root.left and not root.right:
            return sum - root.val == 0
        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)

404. 左叶子之和

https://leetcode-cn.com/problems/sum-of-left-leaves/

计算给定二叉树的所有左叶子之和。

示例:

    3
   / \
  9  20
    /  \
   15   7

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

题解

一:纯粹的递归。

class Solution(object):
    def sumOfLeftLeaves(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if not root:
            return 0
        left_leaf = 0
        if root.left and not root.left.right and not root.left.left:
            left_leaf = root.left.val
        return self.sumOfLeftLeaves(root.left) + self.sumOfLeftLeaves(root.right) + left_leaf
发布了46 篇原创文章 · 获赞 1 · 访问量 5030

猜你喜欢

转载自blog.csdn.net/qq_xuanshuang/article/details/105484471
今日推荐