描述

这是一篇面对初级coder的题解。
知识点:树 递归 DFS
难度:一星


题解

题目:操作给定的二叉树,将其变换为源二叉树的镜像。
比如:    源二叉树 
            8
           /  \
          6   10
         / \  / \
        5  7 9 11
        镜像二叉树
            8
           /  \
          10   6
         / \  / \
        11 9 7  5

考察树的基础知识与递归的思路,深度优先搜索。

方法一:递归求解

思路:递归
本质上是左右子树的交换,通过对左右子树的交换,可以完成二叉树的镜像
机制一:交换 
需要进行左右子树的交换

最通用的思路如上图所示,用一个空指针temp完成交换
机制二:递归
左右节点交换后,继续递归左右子树

一个清晰的版本

class Solution {
public:
    TreeNode* Mirror(TreeNode* pRoot) {
        if(pRoot) //判断边界条件,是否为空树 空树递归结束
        {
            /*交换*/
            TreeNode* temp;//定义一个缓冲指针
            temp=pRoot->left;//缓冲左树
            pRoot->left=pRoot->right;//左树等于右树
            pRoot->right=temp;//右树等于左树(缓冲)
            /*递归*/
            pRoot->left=Mirror(pRoot->left);//递归左树
            pRoot->right=Mirror(pRoot->right);//递归右树
        }
        return pRoot;
    }
};


递归与交换整合

class Solution {
public:
    TreeNode* Mirror(TreeNode* pRoot) {
        if(pRoot) //判断边界条件,是否为空树 空树递归结束
        {
            TreeNode* temp;//定义一个缓冲指针
            temp=Mirror(pRoot->left);//缓冲并镜像左树
            pRoot->left=Mirror(pRoot->right);//左树等于右树
            pRoot->right=temp;//右树等于左树(缓冲)
        }
        return pRoot;
    }
};

用栈实现递归

本质上与函数递归一样,只是手动维护了一个调用栈

#include <stack>
class Solution {
public:
    TreeNode* Mirror(TreeNode* root) {
        if(!root) 
            return root; //判断边界条件
        stack<TreeNode*> stack;//定义递归栈
        TreeNode* temp;//定义一个缓冲指针
        stack.push(root);//压入头节点
        while (!stack.empty())
        {
            TreeNode* node = stack.top();
            //头结点出栈
            stack.pop();
            //将左右节点入栈
            if (node->left) 
                stack.push(node->left);
            if (node->right) 
                stack.push(node->right);
            //交换左右节点
            temp = node->left;
            node->left = node->right;
            node->right = temp;
        }
        return root;
    }
};

复杂度分析:

时间复杂度 O(N) : 其中 NN 为二叉树的节点数量,建立二叉树镜像需要遍历树的所有节点,占用O(N) 时间。
空间复杂度 O(N): 最差情况下(当二叉树退化为链表),递归时系统需使用 O(N) 大小的栈空间。


运行时间8ms 占用内存400KB


总结

递归的解法在树的解题中有广泛应用:

如下动图展示了深度优先搜索的递归算法:

解题模板
下面给出二叉树对称性递归的解题模板
1、递归结束条件:特殊情况的判断
如果是单树问题,一般来说只要进行以下判断:
if(!root) 
    return true/false;
if(!root->left) 
    return true/false/递归函数;
if(!root->right) 
    return true/false/递归函数;

如果是双树问题(根节点分别为p,q),一般来说进行以下判断:
if(!p && !q)
    return true/false;
if(!p || !q)
    return true/false;

当然也不完全是这些情况,比如有的需要加上节点值的判断,需要具体问题需要具体分析
2、返回值
通常对称性递归的返回值是多个条件的复合判断语句
可能是以下几种条件判断的组合:
节点非空的判断
节点值比较判断
(单树)调用根节点左右子树的递归函数进行递归判断
(双树)调用两棵树的左右子树的递归函数进行判断