算法模板-对称性递归

Posted 周先森爱吃素

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法模板-对称性递归相关的知识,希望对你有一定的参考价值。

简介

很多二叉树的题其实都可以通过递归来解决,这些以递归解决二叉树这种对称数据结构的策略,称为对称性递归(symmetric recursion)。

对称性递归

对称性递归,指的是对一个对称的数据结构(典型的是二叉树)从整体对称性思考,将大问题分解为多个小问题,即同时考虑对称的两部分而不是先解决一部分。

不过,可以通过对称性递归解决的问题主要是判断性问题,也就是返回值为bool型的,这种求解类型比较适合递归函数的调用(单值传递)。这类题目一般有两种情况,一种是单树问题,一种是双树问题。前者不需要用到子树的某一部分(如根节点左子树的右子树),只需要利用根节点左右子树的对称性即可进行递归;后者则是题目本身要求比较两棵树,需要两棵树进行判断。

解题模板

二叉树对称性递归的解题模板如下,分为递归边界和返回值两部分。

1.首先是递归边界,也就是特殊情况的判断。
若是单树问题,那么一般如下判断。

if not root: return True/False
if not root.left: return True/False/递归函数调用
if not root.right: return True/False/递归函数调用

若是双树问题,那么一般如下判断。

if not p and not q: return True/False
if not p or not q return True/False

当然,有时候也需要加上节点值的判断。

2.然后就是返回值,通常对称性递归的返回值是多个判断条件组成的复合语句,通常是下面集中判断的组合。

  • 节点非空的判断
  • 节点值比较的判断
  • (单树)调用根节点左右子树的递归函数的判断
  • (双树)调用两颗树的左右子树的递归函数的判断

题目列表

下面是力扣主站题库里可以通过上述解法解题的题目目录。

题解列表

100-相同的树

原题链接

这道题要求判断两棵二叉树是否相同。

边界情况:两棵树都是空树那么必然相同;
返回值:两棵树都非空、根节点值相等、左子树相同、右子树相同。

Python代码如下。

class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        if not p and not q:
            return True

        return bool((p and q) and (p.val == q.val) and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right))

104-二叉树的最大深度

原题链接

这道题要求求一棵二叉树的最大深度。

边界情况:空树的最大深度为0;
返回值:若树非空,则最大深度为左子树最大深度和右子树最大深度的较大者加上1。

Python代码如下。

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

110-平衡二叉树

原题链接

这道题要求判断一棵树是不是平衡二叉树(任一节点左右子树高度差不超过1)。

边界情况:空树是平衡二叉树;
返回值:根的左右子树高度差不大于1、左右子树均是平衡二叉树。

Python代码如下,计算树深度的代码同上一题。

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def height(root):
            if not root:
                return 0
            else:
                return max(height(root.left), height(root.right)) + 1
        if not root:
            return True
        else:
            return abs(height(root.left) - height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)

226-翻转二叉树

原题链接

这道题要求将一棵二叉树镜像翻转。

边界情况:空树的翻转是本身;
返回值:翻转左子树后替换右子树,翻转右子树替换左子树。

Python代码如下。

class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return None
        else:
            root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
            return root

543-二叉树的直径

原题链接

这题要求一棵二叉树的直径。(一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。)

边界情况:空树的最大深度为0;
返回值:若树非空,则最大深度为左子树最大深度和右子树最大深度的较大者加上1。

一棵树的直径就是对每个节点进行判断,找到以该节点为起点向左右子树走经过的节点数,记为 d n o d e = l + r + 1 d_{node} = l + r + 1 dnode=l+r+1。所有节点中最大的 d n o d e d_{node} dnode减去1即为直径。

Python代码如下。

class Solution:
    def diameterOfBinaryTree(self, root: TreeNode) -> int:
        self.rst = 0
        def depth(root):
            if not root:
                return 0
            else:
                l, r = depth(root.left), depth(root.right)
                self.rst = max(l + r + 1, self.rst)
                return max(l, r) + 1
        depth(root)
        return self.rst - 1

572-另一棵树的子树

原题链接

这道题要求判断另一棵树是不是一棵树的子树。

边界情况:若两树中有一者为空则不会存在子树;
返回值:若两棵树不为空,先判断是不是同一棵树,同一棵树就返回True;接着判断一棵树的左子树是否是另一棵树或者一棵树的右子树是否是另一棵树的子树。

Python代码如下,这里求解是否同一棵树用到了之前的代码。

class Solution:
    def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool:
        def isSameTree(p, q):
            if not p and not q:
                return True
            return bool((p and q) and (p.val == q.val) and isSameTree(p.left, q.left) and isSameTree(p.right, q.right))
        if not root or not subRoot:
            return False
        if isSameTree(root, subRoot):
            return True
        return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

617-合并二叉树

原题链接

这题要求合并两个二叉树,对应位置数值相加。

边界情况:两棵树都为空则返回空树;其中任意一棵树为空,返回另一棵树。
返回值:两棵树都不空,则合并后的树节点值为两棵树节点值相加,合并后的左子树为两树的左子树合并的结果,右子树也类似。

Python代码如下。

class Solution:
    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
        if not root1:
            return root2
        if not root2:
            return root1
        if root1 and root2:
            root1.val = root1.val + root2.val
            root1.left = self.mergeTrees(root1.left, root2.left)
            root1.right = self.mergeTrees(root1.right, root2.right)
            return root1

965-单值二叉树

原题链接

这道题要求判断一棵树是不是单值二叉树(每个节点值相同)。

边界情况:空树肯定是单值二叉树;如果左子树非空且左子树根节点值和当前节点值不等则返回False,右子树类似;
返回值:左子树是单值二叉树且右子树也是单值二叉树。

Python代码如下。

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

补充说明

本文启发自一篇力扣题解,简单以力扣主站题库为例介绍了比较简约的对称性递归在实际解题的使用条件和使用方法。

以上是关于算法模板-对称性递归的主要内容,如果未能解决你的问题,请参考以下文章

[算法模板]FFT-快速傅里叶变换

算法漫游指北(第十篇):泛型递归递归代码模板递归思维要点分治算法回溯算法

九十五二叉树的递归和非递归的遍历算法模板

九十五二叉树的递归和非递归的遍历算法模板

二叉树小结

二叉树小结