5道真题训练|学会了二叉树的前世今生(二)

很多朋友都问我学完基础知识以后怎样提高编程水平?当然是刷题啦!很多小伙伴都在纠结从哪里开始,今天给大家推荐一个身边朋友都在使用的刷题网站:点击进入牛客网刷题吧!

在这里插入图片描述

今天是Java进阶刷题的第三天,结合经典算法学习Java语法!一起升级打怪吧!!

文章目录

  • 问题1: 对称的二叉树
    • 描述
    • 示例
    • 题解
  • 问题2:合并二叉树
    • 描述
    • 示例
    • 题解
  • 问题3:二叉树的镜像
    • 描述
    • 示例
    • 题解
  • 问题4:重建二叉树
    • 描述
    • 示例
    • 题解
  • 问题5:二叉搜索树与双向链表
    • 描述
    • 示例
    • 题解

问题1: 对称的二叉树

原题:对称二叉树

5道真题训练|学会了二叉树的前世今生(二)_第1张图片

描述

给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)

例如: 下面这棵二叉树是对称的:
5道真题训练|学会了二叉树的前世今生(二)_第2张图片

下面这棵二叉树不对称:

5道真题训练|学会了二叉树的前世今生(二)_第3张图片

数据范围:节点数满足 0≤n≤1000,节点上的值满足 ∣val∣≤1000

要求:空间复杂度 O(n),时间复杂度 O(n)

备注:你可以用递归和迭代两种方法解决这个问题

示例

示例1

输入:{1,2,2,3,4,4,3}
返回值:true

示例2

输入:{8,6,9,5,7,7,5}
返回值:false

题解

Java代码实现:

public class Solution {
    boolean recursion(TreeNode root1, TreeNode root2){
        //可以两个都为空
        if(root1 == null && root2 == null)
            return true;
        //只有一个为空或者节点值不同,必定不对称
        if(root1 == null || root2 == null || root1.val != root2.val)
            return false;
        //每层对应的节点进入递归比较
        return recursion(root1.left, root2.right) && recursion(root1.right, root2.left);
    }
    boolean isSymmetrical(TreeNode pRoot) {
        return recursion(pRoot, pRoot);
    }
}

思路:前序遍历的时候我们采用的是“根左右”的遍历次序,如果这棵二叉树是对称的,即相应的左右节点交换位置完全没有问题,那我们是不是可以尝试“根右左”遍历,按照轴对称图像的性质,这两种次序的遍历结果应该是一样的。

不同的方式遍历两次,将结果拿出来比较看起来是一种可行的方法,但也仅仅可行,太过于麻烦。我们不如在遍历的过程就结果比较了。而遍历方式依据前序递归可以使用递归。


问题2:合并二叉树

原题:合并二叉树

5道真题训练|学会了二叉树的前世今生(二)_第4张图片

描述

已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。例如,两颗二叉树是:

Tree1:
5道真题训练|学会了二叉树的前世今生(二)_第5张图片
Tree2:
5道真题训练|学会了二叉树的前世今生(二)_第6张图片
合并后的树为:
5道真题训练|学会了二叉树的前世今生(二)_第7张图片

数据范围:树上节点数量满足 0≤n≤500,树上节点的值一定在32位整型范围内。

进阶:空间复杂度 O(1) ,时间复杂度 O(n)

示例

示例1

输入:{1,3,2,5},{2,1,3,#,4,#,7}
返回值:{3,4,5,5,4,#,7}

说明:如题面图

示例2

输入:{1},{}
返回值:{1}

题解

Java代码实现:

import java.util.*;
public class Solution {
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        //若只有一个节点返回另一个,两个都为null自然返回null
        if (t1 == null)
            return t2;
        if (t2 == null)
            return t1;
        //根左右的方式递归
        TreeNode head = new TreeNode(t1.val + t2.val);
        head.left = mergeTrees(t1.left, t2.left);
        head.right = mergeTrees(t1.right, t2.right);
        return head;
    }
}

思路: 要将一棵二叉树的节点与另一棵二叉树相加合并,肯定需要遍历两棵二叉树,那我们可以考虑同步遍历两棵二叉树,这样就可以将每次遍历到的值相加在一起。遍历的方式有多种,这里推荐前序递归遍历。


问题3:二叉树的镜像

原题:二叉树的镜像

5道真题训练|学会了二叉树的前世今生(二)_第8张图片

描述

操作给定的二叉树,将其变换为源二叉树的镜像。

数据范围:二叉树的节点数 0≤n≤1000 , 二叉树每个节点的值 0≤val≤1000

要求: 空间复杂度 O(n) 。本题也有原地操作,即空间复杂度 O(1) 的解法,时间复杂度 O(n)

比如:源二叉树
5道真题训练|学会了二叉树的前世今生(二)_第9张图片

镜像二叉树
5道真题训练|学会了二叉树的前世今生(二)_第10张图片

示例

示例1

输入:{8,6,10,5,7,9,11}
返回值:{8,10,6,11,9,7,5}

说明:如题面所示

示例2

输入:{}
返回值:{}

题解

Java代码实现:

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    public TreeNode Mirror (TreeNode pRoot) {
        // write code here
        if(pRoot == null) return null;
        // 构建辅助栈
        Stack<TreeNode> stack = new Stack<>();
        // 根节点入栈
        stack.add(pRoot);
        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 pRoot;
    }
}

思路:主要是利用栈(或队列)遍历树的所有节点 node ,并交换每个 node 的左 / 右子节点。


问题4:重建二叉树

原题:重建二叉树

5道真题训练|学会了二叉树的前世今生(二)_第11张图片

描述

给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

5道真题训练|学会了二叉树的前世今生(二)_第12张图片

提示:

1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比

数据范围:n≤2000,节点的值 −10000≤val≤10000

要求:空间复杂度 O(n),时间复杂度 O(n)

示例

示例1

输入:[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]
返回值:{1,2,3,4,#,5,6,#,7,#,#,8}

说明:返回根节点,系统会输出整颗二叉树对比结果,重建结果如题面图示

示例2

输入:[1],[1]
返回值:{1}

示例3

输入:[1,2,3,4,5,6,7],[3,2,4,1,6,5,7]
返回值:{1,2,5,3,4,6,7}

题解

Java代码实现:

public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        return dfs(0, 0, in.length - 1, pre, in);
    }
     
    public TreeNode dfs(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) {
        if (preStart > preorder.length - 1 || inStart > inEnd) {
            return null;
        }
        //创建结点
        TreeNode root = new TreeNode(preorder[preStart]);
        int index = 0;
        //找到当前节点root在中序遍历中的位置,然后再把数组分两半
        for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == root.val) { index = i; break; } } root.left = dfs(preStart + 1, inStart, index - 1, preorder, inorder); root.right = dfs(preStart + index - inStart + 1, index + 1, inEnd, preorder, inorder); return root; }

思路:二叉树的前序遍历:根左右;中序遍历:左根右。设置三个指针,一个是preStart,表示的是前序遍历开始的位置,一个是inStart,表示的是中序遍历开始的位置。一个是inEnd,表示的是中序遍历结束的位置,我们主要是对中序遍历的数组进行拆解


问题5:二叉搜索树与双向链表

原题:二叉搜索树与双向链表

5道真题训练|学会了二叉树的前世今生(二)_第13张图片

描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示

5道真题训练|学会了二叉树的前世今生(二)_第14张图片

数据范围:输入二叉树的节点数 0≤n≤1000,二叉树中每个节点的值 0≤val≤1000

要求:空间复杂度O(1)(即在原树上操作),时间复杂度 O(n)

注意:

1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出

输入描述: 二叉树的根节点
返回值描述: 双向链表的其中一个头节点。

示例

示例1

输入:{10,6,14,4,8,12,16}
返回值:From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;

说明:输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。

示例2

输入:{5,4,#,3,#,2,#,1}
返回值:From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1;

题解

Java代码实现:

public class Solution {
    TreeNode pre=null;
    TreeNode root=null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree==null)
            return null;
        // 递归遍历左子树
        Convert(pRootOfTree.left);
        // 判断特殊情况
        if (root==null){
            root=pRootOfTree;
        }
        // 修改遍历的结点为双向链表
        if (pre!= null){
            pRootOfTree.left=pre;
            pre.right=pRootOfTree;
        }
        // 更新 pre
        pre=pRootOfTree;
        // 递归遍历右子树
        Convert(pRootOfTree.right);
        return root;
    }
}

你可能感兴趣的:(牛客网,刷题进阶,java,算法,开发语言)