【算法刷题 | 二叉树 04】3.27(翻转二叉树、对称二叉树、完全二叉树的节点个数、平衡二叉树、完全二叉树的所有路径)

文章目录

  • 6.翻转二叉树
    • 6.1问题
    • 6.2解法一:递归
      • 6.2.1递归思路
        • (1)确定递归函数的参数和返回值
        • (2)确定终止条件
        • (3)确定单层递归的逻辑
      • 6.2.2全部代码
    • 6.3解法二:层序遍历
  • 7.对称二叉树
    • 7.1问题
    • 7.2解法一:递归
      • 7.2.1递归思路
        • (1)确定递归函数的参数和返回值
        • (2)确定终止条件
        • (3)确定单层递归的逻辑
      • 7.2.2代码实现
    • 7.3解法二:迭代法
  • 8.完全二叉树的节点个数
    • 8.1问题
    • 8.2解法一:递归
    • 8.3解法二:层序遍历
  • 9.平衡二叉树
    • 9.1问题
    • 9.2解法一:递归
      • 9.2.1递归思路
        • (1)确定递归函数返回值和参数值
        • (2)确定终止条件
        • (3)确定递归逻辑
      • 9.2.2代码
  • 10.完全二叉树的所有路径
    • 10.1问题
    • 10.2解法一:前序遍历+回溯
      • 10.2.1递归思路
        • (1)确定递归函数参数以及返回值
        • (2)确定递归终止条件
        • (3)确定递归逻辑
      • 10.2.2代码实现

6.翻转二叉树

6.1问题

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

  • 示例一:

img

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

6.2解法一:递归

6.2.1递归思路

(1)确定递归函数的参数和返回值
  • 题目为翻转根节点的左右孩子
  • 最后返回根节点,即每次递归,传入TreeNode节点,返回该节点
TreeNode reverse(TreeNode node);
(2)确定终止条件
  • 当递归到的该节点为空,即返回
if(node==null){
	return;
}
(3)确定单层递归的逻辑
  • 当确定该节点不为空,先交换左、右孩子
  • 再分别递归左孩子、右孩子
swap(node);
reverse(node.left);
reverse(node.right);

6.2.2全部代码

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return root;
        }
        return reverse(root);
    }

    private TreeNode reverse(TreeNode node){
        if(node==null){
            return node;
        }
        swap(node);
        reverse(node.left);
        reverse(node.right);
        return node;
    }

    private void swap(TreeNode node){
        TreeNode tmp=node.left;
        node.left=node.right;
        node.right=tmp;
    }
}

6.3解法二:层序遍历

  1. 将每一个从队列取出来的元素,进行左孩子和有孩子的交换
class Solution {
    public TreeNode invertTree(TreeNode root) {

        //广度优先遍历
        Queue<TreeNode> queue=new LinkedList<>();

        if(root==null){
            return root;
        }
        
        queue.offer(root);
        while(!queue.isEmpty()){
            int size=queue.size();
            while(size>0){
                TreeNode node=queue.poll();
                swap(node);
                if(node.left!=null){
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    queue.offer(node.right);
                }
                size--;
            }
        }
        return root;
    }

    private void swap(TreeNode node){
        TreeNode tmp=node.left;
        node.left=node.right;
        node.right=tmp;
    }
}

7.对称二叉树

7.1问题

给你一个二叉树的根节点 root , 检查它是否轴对称。

  • 示例一:

img

输入:root = [1,2,2,3,4,4,3]
输出:true

7.2解法一:递归

7.2.1递归思路

(1)确定递归函数的参数和返回值
  1. 比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点
  2. 返回值为boolean类型
boolean compare(TreeNode left,TreeNode right)
(2)确定终止条件
  1. 首先排除左孩子、右孩子节点有空的情况
    • 左孩子为空,右孩子不为空:return false
    • 左孩子不为空,右孩子为空:return false
    • 左、右孩子均为空:return true
  2. 左、右孩子均不为空:
    • 比较左右孩子的数值,不相同:return false
if (left == NULL && right != NULL) 
	return false;
else if (left != NULL && right == NULL) 
    return false;
else if (left == NULL && right == NULL) 
    return true;
else if (left->val != right->val) 
    return false; // 注意这里我没有使用else
(3)确定单层递归的逻辑
  • 单层递归的逻辑就是处理左右节点都不为空,且数值相同的情况。
    • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
    • 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
    • 如果左右都对称就返回true ,有一侧不对称就返回false 。
boolean outside = compare(left.left, right.right);   // 左子树:左、 右子树:右
boolean inside = compare(left.right, right.left);    // 左子树:右、 右子树:左
boolean isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

7.2.2代码实现

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return compare(root.left,root.right);
    }

    private boolean compare(TreeNode left,TreeNode right){
        if(left==null && right!=null){
            return false;
        }else if(left!=null && right==null){
            return false;
        }else if(left==null && right==null){
            return true;
        }else if(left.val!=right.val){
            return false;
        }

        //单层递归逻辑
        boolean out=compare(left.left,right.right);
        boolean in=compare(left.right,right.left);
        return (out&&in);

    }
}

7.3解法二:迭代法

  1. 使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历

101.对称二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        
        //迭代法
        if(root==null){
            return true;
        }

        Queue<TreeNode> queue=new LinkedList<>();

        //添加根节点的左右孩子
        queue.offer(root.left);
        queue.offer(root.right);

        while(!queue.isEmpty()){
            TreeNode left=queue.poll();
            TreeNode right=queue.poll();

            //1、判断两个节点是否均为空
            if(left==null && right==null){
                continue;   //对称,结束此次循环,再次取出新的两个节点判断
            }
            //2、判断不符合对称条件
            if(left==null || right==null || (left.val!=right.val)){
                return false;
            }
            //3、添加新的两个节点:外层+内层
            queue.offer(left.left);
            queue.offer(right.right);

            queue.offer(left.right);
            queue.offer(right.left);
        }
        return true;
    }

    
}

8.完全二叉树的节点个数

8.1问题

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

  • 示例一:

img

输入:root = [1,2,3,4,5,6]
输出:6

8.2解法一:递归

class Solution {
    public int countNodes(TreeNode root) {
        return count(root);
    }

    private int count(TreeNode node){
        if(node==null){
            return 0;
        }
        int leftCount=count(node.left);
        int rightCount=count(node.right);
        return leftCount+rightCount+1;
    }
}

8.3解法二:层序遍历

class Solution {
    public int countNodes(TreeNode root) {

        //广度优先遍历
        Queue<TreeNode> queue=new LinkedList<>();
        int count=0;

        if(root==null){
            return count;
        }

        queue.offer(root);
        while(!queue.isEmpty()){
            int size=queue.size();
            count+=size;
            while(size>0){
                TreeNode node=queue.poll();

                if(node.left!=null){
                    queue.offer(node.left);
                }
                if(node.right!=null){
                    queue.offer(node.right);
                }
                size--;
            }
        }
        return count;
    }

    
}

9.平衡二叉树

9.1问题

给定一个二叉树,判断它是否是 平衡二叉树

  • 示例一:

img

输入:root = [3,9,20,null,null,15,7]
输出:true

9.2解法一:递归

9.2.1递归思路

(1)确定递归函数返回值和参数值
  1. 题目为确定一棵树是否为平衡树
  2. 平衡树的定义:一棵树为空或者其左右节点的高度差的绝对值不超过1
  3. 即递归函数参数为一个树节点,返回值为该节点的高度(注意:若返回-1,则表明该树不平衡)
int isBalancedTree(TreeNode node)
(2)确定终止条件
  1. 若该节点为null,返回0
if(node==null){
	return 0;
}
(3)确定递归逻辑
  1. 传入一个节点,要求返回其高度,即需要求其左、右节点的高度
  2. 分别求完左、右节点的高度之后,判断其中是否为-1,若为-1,则返回-1,代表不平衡
  3. 若均不为-1,则求出该节点的平衡因子,若其绝对值超过1,则返回-1,代表不平衡
  4. 否则返回当前节点为根节点的树的最大高度
int leftHeight=isBalancedTree(node.left);
int rightHeight=isBalancedTree(node.right);
if(leftHeight==-1 || rightHeight==-1){
    return -1;
}
if(Math.abs(leftHeight-rightHeight)>1){
    return -1;
}
return 1+Math(leftHeight,rightHeight);

9.2.2代码

class Solution {
    public boolean isBalanced(TreeNode root) {
        return isBalancedTree(root)!=-1;
    }

    private int isBalancedTree(TreeNode node){
        if(node==null){
            return 0;
        }
        int leftHeight=isBalancedTree(node.left);
        int rightHeight=isBalancedTree(node.right);
        if(leftHeight==-1 || rightHeight==-1){
            return -1;
        }
        if(Math.abs(leftHeight-rightHeight)>1){
            return -1;
        }
        return 1+Math.max(leftHeight,rightHeight);
    }
}

10.完全二叉树的所有路径

10.1问题

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

  • 示例一:

img

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]

10.2解法一:前序遍历+回溯

  1. 题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径
  2. 把路径记录下来,需要回溯来回退一个路径再进入另一个路径。

image-20240327153241191

10.2.1递归思路

(1)确定递归函数参数以及返回值
  1. 求以node为根节点到达叶子节点的路径
  2. paths存放路径值
  3. res存放最终结果
void traversal(TreeNode node,List<Integer> paths,List<String> res)
(2)确定递归终止条件
  1. 当遍历到了叶子节点,即为一条完整的路径
  2. 取出paths的全部节点,并加入到res中
  3. 直接return
if(node.left==null && node.right==null){
    // 输出
    StringBuilder sb = new StringBuilder();// StringBuilder用来拼接字符串,速度更快
    for (int i = 0; i < paths.size() - 1; i++) {
    	sb.append(paths.get(i)).append("->");
    }
    sb.append(paths.get(paths.size() - 1));// 记录最后一个节点
    res.add(sb.toString());// 收集一个路径
    return;
}
(3)确定递归逻辑
 		// 递归和回溯是同时进行,所以要放在同一个花括号里
        if (root.left != null) { // 左
            traversal(root.left, paths, res);
            paths.remove(paths.size() - 1);// 回溯
        }
        if (root.right != null) { // 右
            traversal(root.right, paths, res);
            paths.remove(paths.size() - 1);// 回溯
        }

10.2.2代码实现

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<Integer> paths=new ArrayList<>();
        List<String> res=new ArrayList<>();
        traversal(root,paths,res);
        return res;
    }

    private void traversal(TreeNode node,List<Integer> paths,List<String> res){
        
        //1、前序遍历(中左右)处理该节点
        paths.add(node.val);

        //2、终止条件:该节点为叶子节点
        if(node.left==null && node.right==null){
            StringBuilder sb=new StringBuilder();
            for(int i=0;i<paths.size()-1;i++){
                sb.append(paths.get(i)).append("->");
            }
            //加入最后一个节点
            sb.append(paths.get(paths.size()-1));
            res.add(sb.toString());
            return;
        }

        //3、递归逻辑+回溯
        if(node.left!=null){
            traversal(node.left,paths,res);
            //回溯
            paths.remove(paths.size() - 1); //去除最后一个节点
        }

        if(node.right!=null){
            traversal(node.right,paths,res);
            //回溯
            paths.remove(paths.size() - 1); //去除最后一个节点
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/493205.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQLynx发布3.0.0版本:带来更流畅便捷的SQL开发体验

作为新一代的一站式数据库管理开发工具&#xff0c; SQLynx自发布上线以来&#xff0c;一直受到广大用户的好评与鼓励。 为了给用户提供更高效、更便捷、更可靠的数据库管理开发体验&#xff0c;SQLynx今日正式发布3.0.0版本&#xff0c;同步在麦聪软件官网上线&#xff0c;全…

k8s入门到实战(十四)—— Helm详细介绍及使用

Helm 使用 Helm 是一个 k8s 应用的包管理工具&#xff0c;类似于 Ubuntu 的 APT 和 CentOS 中的 YUM。 Helm 使用 chart 来封装 k8s 应用的 yaml 文件&#xff0c;我们只需要设置自己的参数&#xff0c;就可以实现自动化的快速部署应用。 Helm 通过打包的方式&#xff0c;支…

常用的AD规则设置

目录 规则编辑器&#xff1a; 间距规则&#xff1a; 线宽规则&#xff1a; 过孔规则&#xff1a; 铺铜设置&#xff1a; 生成制造过孔&#xff1a; 过孔之间间距&#xff1a; 最小阻焊层间距&#xff1a; 丝印到阻焊的距离&#xff1a; 丝印到丝印距离&#xff1a; 走…

mysql 高阶语句 与视图

目录 一 前言 二 msql 高阶语句使用方法 &#xff08;一&#xff09; 查询并排序&#xff08;order by&#xff09; 1&#xff0c;排序方式 2&#xff0c;查询指定列 并排序 3, 条件判断&#xff08;过滤指定行&#xff09; 再查询指定列 并排序 4&#xff0c;查…

Android Viewpager 内外间距

Android使用Viewpager_内外边距 代码&#xff1a; 1、adapter&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_par…

Ubuntu20.04 安装 OpenCV3 过程中遇到的各种问题及其解决办法

文章目录 前言开始安装OpenCV3问题1&#xff1a;ICV: Failed to download ICV package: ippicv_linux_20151201.tgz.1.1 具体步骤 问题2&#xff1a;/usr/include/c/7/cstdlib:75:15: fatal error: stdlib.h: No such file or directory问题3&#xff1a;error: CODEC_FLAG_GLO…

安装paddle detection心得

一、安装PaddlePaddle conda create -n mypaddle python3.8 conda activate mypaddle python -m pip install paddlepaddle-gpu2.6.0 -i https://mirror.baidu.com/pypi/simple 请确保您的PaddlePaddle安装成功并且版本不低于需求版本。使用以下命令进行验证。 这是CUDA1…

通过修改ospf的COST值来控制路由选路

配置好OSPF之后,发现默认走的是上面 PC1>tracert 192.168.200.1traceroute to 192.168.200.1, 8 hops max (ICMP), press Ctrl+C to stop1 192.168.100.254 16 ms <1 ms 16 ms2 10.10.10.2 15 ms &l

科普 | Runes 预挖矿概念

作者&#xff1a;Jacky X/推&#xff1a;zxl2102492 关于 Runes 协议的前世今生&#xff0c;可以点击阅读这篇文章 &#x1f447; 《简述 Runes 协议、发展历程及最新的「公开铭刻」发行机制的拓展讨论》 什么是传统预挖矿概念 这轮比特币生态爆发之前&#xff0c;预挖矿&…

基于java+springboot+vue实现的超市货品信息管理系统(文末源码+Lw+ppt)23-355

摘 要 随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的超市货品信息管理系统。当前的信息管理…

YOLOv9改进策略:注意力机制 | 二阶通道注意力机制(Second-order Channel Attention,SOCA),实现单图超分效果

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;CVPR_2019 SOCA注意力&#xff0c;一种基于二阶通道注意力机制&#xff0c;能够单幅图像超分辨率&#xff0c;从原理角度分析能够在小目标检测领域实现大幅涨点效果&#xff01;&#xff01;&#xff01; &am…

APP测试常见功能测试点汇总

1、安装和卸载 安装和卸载是任何一款APP中都属于最基本功能。一旦出错&#xff0c;就属于优先级为紧要的BUG。因此APP的安装和卸载应作为一个测试点多加重视。 1 应用是否可以正常安装&#xff08;命令行安装&#xff1b;豌豆荚&#xff0f;手机助手等第三方软件安装&#xff…

C语言看完我这篇编译与链接就够啦!!!

1. 前言 Hello&#xff01;大家好我是小陈&#xff0c;今天来给大家介绍最详细的C语言编译与链接。 2. 编译和链接 我们通常用的编译器&#xff0c;比如Visual Sudio,这样的IDE(集成开发环境&#xff09;一般将编译和链接的过程一步完成&#xff0c;通常将这这种编译和链接合…

冗余双写方案下数据一致性问题解决及延申问题处理方案

主要整理了采用冗余双写方案后的问题解决方案。 1、问题&#xff1a;冗余双写场景下&#xff0c;如何解决数据一致性问题&#xff1f; 方案一&#xff1a; 直接RPC调用Seata分布式事务框架&#xff0c;采用该方式实现了事务的强一致性&#xff0c;代码逻辑简单的同时业务侵入…

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i、EuRoC 和 TUM-VI 运行测试

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i、EuRoC 和 TUM-VI 运行测试 1 Prerequisites1.1 C11 or C0x Compiler1.2 Pangolin1.3 OpenCV1.4 Eigen3 2 安装 Intel RealSense™ SDK 2.02.1 测试设备2.2 编译源码安装 (Recommend)2.3 预编译包安装 3 编译 ORB-S…

网络编程基本概念(一篇文章掌握基本内容的详细概念,IP,端口号,协议,协议分层,封装和分用,客户端和服务端,请求和回应,两台主机的通信)

IP地址 概念 IP地址主要⽤于标识⽹络主机、其他⽹络设备&#xff08;如路由器&#xff09;的⽹络地址。简单说&#xff0c;IP地址⽤于定位主机的⽹络地址。 就像我们发送快递⼀样&#xff0c;需要知道对⽅的收货地址&#xff0c;快递员才能将包裹送到⽬的地。 IP的格式 IP地址…

优化iproute2中的tc流控规则下发机制

设备基于IP对每个用户配置流量控制规则&#xff0c;规则如下&#xff1a; tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 192.168.0.10 flowid 1:10 上面的tc 是一个配置工具&#xff0c;本身是一个应用程序&#xff0c;tc后面的参数通过应用程序参…

vue3+threejs新手从零开发卡牌游戏(十八):己方场上手牌添加画线

手牌上场后&#xff0c;点击己方怪兽区卡牌会跟随鼠标移动画出线条&#xff0c;之后可以通过判断鼠标移动到对方场地的某卡牌进行战斗操作&#xff0c;代码主要改动在game/index.vue文件。 1.添加鼠标移动监听事件&#xff08;移动端&#xff09;&#xff1a; window.addEven…

Scikit Learn中的概率校准曲线

概率校准是一种用于将二分类的输出分数转换为概率的技术&#xff0c;以与目标类的实际概率相关联。在本文中&#xff0c;我们将讨论概率校准曲线以及如何使用Scikit-learn绘制它们。 概率校准 概率校准曲线是二分类问题的正类的预测概率和实际观察频率之间的图。它用于检查分…

DLS-42/5-5双位置继电器 柜内安装板前接线 JOSEF约瑟

系列型号&#xff1a; DLS-41/10-2双位置继电器&#xff1b; DLS-41/9-3双位置继电器&#xff1b; DLS-41/8-4双位置继电器&#xff1b; DLS-41/6-6双位置继电器&#xff1b; DLS-42/9-1双位置继电器&#xff1b; DLS-42/8-2双位置继电器&#xff1b; DLS-42/7-3双位置继…