101. 对称二叉树

如果一个树的左子树与右子树镜像对称,那么这个树是对称的。

  • 它们的两个根结点具有相同的值
  • 每个树的 右子树 都与另一个树的 左子树 镜像对称

Leetcode 101~120_算法

递归结束条件:

  • 都为空指针则返回 True
  • 只有一个为空或两个指针当前节点值是不相等则返回 False

递归过程:

  • 判断 A 的右子树与 B 的左子树是否对称
  • 判断 A 的左子树与 B 的右子树是否对称

方法一:递归

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:        
        def check(p, q):
            if not (p or q): return True
            if not p or not q or p.val != q.val: return False
        	#if not (p and q and p.val == q.val): return False
            return check(p.left, q.right) and check(p.right, q.left) 

        return check(root, root)

广度遍历

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def helper(node, level):
            if not node: 
                res[level-1].append(None)
                return
            else:
                res[level-1].append(node.val)
                if len(res) == level:  # 遍历到新层时,只有最左边的结点使得等式成立
                    res.append([])
                helper(node.left, level+1)
                helper(node.right, level+1)
        res = [[]]
        helper(root, 1)
        for i in res[:-1]:
            if i != i[::-1]:return False
        return True

方法二:迭代

初始化队列时把根节点入队两次。每次提取两个连续的结点进行比较,然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者检测到树不对称时,结束。

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:        
        q = deque([root, root])
        while q:
            u = q.popleft()
            v = q.popleft()

            if not u and not v: continue
            if not u or not v or u.val != v.val:
                return False

            q.extend([u.left, v.right])            
            q.extend([u.right, v.left])

        return True

广度遍历

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:        
        queue = [root]
        while queue:
            temp = []
            layer = []     
            while queue:
                cur = queue.pop()
                if cur:
                    layer.append(cur.val)
                    temp.append(cur.left)
                    temp.append(cur.right)
                else:
                    layer.append(None)
            if layer != layer[::-1]:return False
            queue = temp

        return True

104. 二叉树的最大深度

111. 二叉树的最小深度

方法一:深度优先搜索 DFS

class Solution:
    def maxDepth(self, root: TreeNode) -> int:        
        return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1 if root else 0

方法二:广度优先搜索 BFS

存放一层,处理一层。

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root:return 0
        res, q = 0, [root]

        while q:
            res += 1
            temp = []

            while q:
                cur = q.pop() 
                if cur.left: temp.append(cur.left)               
                if cur.right: temp.append(cur.right) 
            q = temp

        return res
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
        res = 0
        que = collections.deque([(root, 1)])
        while que:
            node, depth = que.popleft()
            res = max(res, depth) 
            if node.left:
                que.append((node.left, depth + 1))
            if node.right:
                que.append((node.right, depth + 1))
        
        return res

111. 二叉树的最小深度

104. 二叉树的最大深度

方法一:深度优先搜索

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root: return 0
        if not root.left and not root.right: return 1
        
        min_depth = 10**9
        if root.left:
            min_depth = min(self.minDepth(root.left), min_depth)
        if root.right:
            min_depth = min(self.minDepth(root.right), min_depth)

        return min_depth + 1

方法二:广度优先搜索

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:return 0
        res, q = 0, [root]

        while q:
            res += 1
            temp = []

            while q:
                cur = q.pop() 
                if cur.left: temp.append(cur.left)               
                if cur.right: temp.append(cur.right)
                if not cur.left and not cur.right:return res 
            q = temp

        return res
class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root: return 0

        que = collections.deque([(root, 1)])
        while que:
            node, depth = que.popleft()
            if not node.left and not node.right:
                return depth
            if node.left:
                que.append((node.left, depth + 1))
            if node.right:
                que.append((node.right, depth + 1))
        
        return 0

112. 路径总和

根结点到叶子结点的路径上值的和 :在叶子结点上判断。

方法一:递归 DFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:return False
        if not root.left and not root.right: # 叶子结点
            return root.val == targetSum
        # 问题转化为左右子树递归
        return self.hasPathSum(root.right, targetSum - root.val) or self.hasPathSum(root.left, targetSum - root.val)

方法二:广度优先搜索 BFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root: return False
        q = deque([(root, root.val)]) # 通过元组携带值
        while q:
            cur, tem = q.popleft()
            if not cur.left and not cur.right: # 叶子结点
                if tem == targetSum: return True
                continue
                
            cur.left and q.append((cur.left, cur.left.val + tem))  
            cur.right and q.append((cur.right, cur.right.val + tem))      
        
        return False

112. 路径总和

根结点到叶子结点的路径上值的和 :在叶子结点上判断。

方法一:递归 DFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:return False
        if not root.left and not root.right: # 叶子结点
            return root.val == targetSum
        # 问题转化为左右子树递归
        return self.hasPathSum(root.right, targetSum - root.val) or self.hasPathSum(root.left, targetSum - root.val)

方法二:广度优先搜索 BFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root: return False
        q = deque([(root, root.val)]) # 通过元组携带值
        while q:
            cur, tem = q.popleft()
            if not cur.left and not cur.right: # 叶子结点
                if tem == targetSum: return True
                continue
                
            cur.left and q.append((cur.left, cur.left.val + tem))  
            cur.right and q.append((cur.right, cur.right.val + tem))      
        
        return False

113. 路径总和 II

方法一:DFS

cclass Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:

        def dfs(cur, tem):
            path.append(cur.val)
            tem -= cur.val

            if not (cur.left or cur.right or tem):
                res.append(path[:]) # copy
            
            cur.left and dfs(cur.left, tem)
            cur.right and dfs(cur.right, tem)
            path.pop() # 回溯

        if not root:return []
        res , path = [], []
        dfs(root, targetSum)
        
        return res

方法二:广度优先搜索

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root: return [] 
        res = []
        q = deque([(root, [], targetSum)])  # 结点,路径,路径和

        while q:
            cur, path, tem = q.popleft()
            # path += [cur.val]
            # path.append(cur.val) # 列表 +=,append 对象不变 !!! 
            path = path + [cur.val] # 对象变了
            tem -= cur.val
            # 如果是叶子节点,同时和为零。
            if not cur.left and not cur.right and not tem: 
                    res.append(path) # 保存路径

            cur.left and q.append((cur.left, path, tem))
            cur.right and q.append((cur.right, path, tem))

        return res

114. 二叉树展开为链表

118. 杨辉三角

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        res = []
        for i in range(numRows):
            tmp = [1] * (i+1)
            for j in range(1,i):
                tmp[j] = res[-1][j-1]+res[-1][j]

            res.append(tmp)
      
        return res

119. 杨辉三角 II

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        res = []
        for i in range(rowIndex+1):
            tmp = [1] * (i+1)
            for j in range(1,i):
                tmp[j] = res[j-1] + res[j]

            res = tmp
      
        return res

使用一个数组,从上向下遍历,从右向左刷新;从前往后或从后往前,res[j] 都会被覆盖,从后往前用的是 res[j-1]。

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        res = [1] * (rowIndex + 1) # 元素个数为 rowIndex + 1

        for i in range(rowIndex + 1):
            # i-1 跳过最后一个,0 跳过第一个 。
            for j in range(i-1, 0, -1): 
                res[j] += res[j - 1]

        return res