二叉树的镜像(剑指offer 27)Java递归(dfs)+辅助栈两种方法实现

简介: 二叉树的镜像(剑指offer 27)Java递归(dfs)+辅助栈两种方法实现

一、题目描述



请完成一个函数,输入一个二叉树,该函数输出它的镜像。


例如输入:

    4

  /   \

 2     7

/ \   / \

1   3 6   9


镜像输出:

    4

  /   \

 7     2

/ \   / \

9   6 3   1


示例 1:

输入:root = [4,2,7,1,3,6,9]

输出:[4,7,2,9,6,3,1]


限制:

0 <= 节点个数 <= 1000


二、思路讲解



1、方法一:递归(dfs

       

和树有关的题目一般都离不开深度优先遍历。


我们将根节点的左右子树调换,然后将他的左子树的左右子树调换、将它的右子树的左右子树调换……这就是递归的思路了。

     

然后是跳出递归的条件:如果给的树为空,或者是已经越过了叶子节点


2、方法二:辅助栈



因为要把每一个节点的左右节点调换位置,自然而然能想到先进后出的栈。

 

利用辅助栈来遍历二叉树所有的节点。


先将根节点入栈,再出栈,每次将栈弹出的元素的左右子节点,再交换左右子节点;然后弹出左子节点,再将它的左右子节点入栈,并且在树上交换左右子节点……然后弹出右子节点,重复着这个过程,直到栈中没有元素,此时二叉树遍历完成。


这里我可能讲得不是很清楚,附上力扣原作者的题解:


https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/solution/mian-shi-ti-27-er-cha-shu-de-jing-xiang-di-gui-fu-/  


三、Java代码实现



1、递归


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null){
            return root;
        }
        TreeNode temp = root.right;
        root.right = mirrorTree(root.left);
        root.left = mirrorTree(temp);
        return root;
    }
}


2、辅助栈  


class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) return null;
        Stack<TreeNode> stack = new Stack<>() {{ add(root); }};
        while(!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if(node.left != null) stack.add(node.left);
            if(node.right != null) stack.add(node.right);
            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;
        }
        return root;
    }
}


四、时空复杂度分析



1、递归  

     

时间复杂度:        O(N)        遍历整个二叉树

     

空间复杂度:        O(N)        最差情况下(当二叉树退化为链表),递归时系统需要O(N)大小的栈空间


2、辅助栈

     

时间复杂度 O(N)         其中 NN 为二叉树的节点数量,建立二叉树镜像需要遍历树的所有节点,占用 O(N)O(N) 时间。

     

空间复杂度 O(N)        如下图所示,最差情况下,栈 stackstack 最多同时存储(N+1)/2个节点,占用 O(N)额外空间。


ee4f7f11f00b4e6a946daae0eba6a973.png




相关文章
|
4天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
31 17
|
4天前
|
存储 算法 Java
🧠Java零基础 - Java栈(Stack)详解
【10月更文挑战第17天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
10 2
|
4天前
|
存储 缓存 Java
Java应用瘦身记:Docker镜像从674MB优化至58MB的实践指南
【10月更文挑战第22天】 在容器化时代,Docker镜像的大小直接影响到应用的部署速度和运行效率。一个轻量级的Docker镜像可以减少存储成本、加快启动时间,并提高资源利用率。本文将分享如何将一个Java基础Docker镜像从674MB缩减到58MB的实践经验。
11 1
|
6天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
11 3
|
6天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
9 2
|
6天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
8 1
|
6天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
16 1
|
4天前
|
算法 Java
JAVA 二叉树面试题
JAVA 二叉树面试题
10 0
|
Java
JAVA方法的定义
JAVA方法的定义
77 0
|
5月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
39 1