想要精通算法和SQL的成长之路 - 验证二叉树

news2024/11/18 5:34:04

想要精通算法和SQL的成长之路 - 验证二叉树

  • 前言
  • 一. 验证二叉树
    • 1.1 并查集
    • 1.2 入度以及边数检查

前言

想要精通算法和SQL的成长之路 - 系列导航
并查集的运用

一. 验证二叉树

原题链接
在这里插入图片描述
思路如下:

  1. 对于一颗二叉树,我们需要做哪些校验?

  2. 首先这颗树不可以成环,如图:
    在这里插入图片描述

  3. 其次,这颗树的边数量,应该等于 n -1。如下图就是错的:
    在这里插入图片描述

  4. 存在一个根节点,它的入度为0,其他所有的节点,入度都不能够超过1。

那么针对以上几点,我们可以分别来考虑。我们同时遍历一次左右节点数组。值不是-1的话,说明该端连接的节点非空。

  • 我们用一个int[] inDegree数组代表入度。对应值非-1的时候,入度加1。
  • 用一个edges变量代表无向边数,只要值非-1,变数+1。
  • 同时在遍历的过程中,针对值非-1的情况,我们将左右两端的节点进行合并。这一块使用并查集数据结构。最终合并完之后,根节点数应该只有一个。

那么我们先写并查集的数据结构。

1.1 并查集

class UnionFind {
    private int[] parent;
    private int[] rank;
    private int sum;

    public UnionFind(int n) {
        rank = new int[n];
        parent = new int[n];
        // 初始化,每个节点的根节点指向其本身
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
        // 这里指的是根节点数量
        sum = n;
    }

    public int find(int x) {
        while (x != parent[x]) {
            x = parent[x];
        }
        return x;
    }

    public void union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        // 如果两个元素的根节点一致,不需要合并
        if (rootX == rootY) {
            return;
        }
        // 如果根节点 rootX 的深度 > rootY。
        if (rank[rootX] > rank[rootY]) {
            // 那么将以rootY作为根节点的集合加入到rootX对应的集合当中
            rank[rootX] += rank[rootY];
            // 同时改变rootY的根节点,指向rootX。
            parent[rootY] = rootX;
        } else {
            // 反之
            rank[rootY] += rank[rootX];
            parent[rootX] = rootY;
        }
        sum--;
    }
}

1.2 入度以及边数检查

public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
    int[] inDegree = new int[n];
    UnionFind unionFind = new UnionFind(n);
    // 边数
    int edges = 0;
    for (int i = 0; i < n; i++) {
        int left = leftChild[i];
        int right = rightChild[i];
        if (left != -1) {
        	// 入度数+1,并且合并左右两端。同时边数+1
            inDegree[left]++;
            unionFind.union(i, left);
            edges++;
        }
        if (right != -1) {
            inDegree[right]++;
            unionFind.union(i, right);
            edges++;
        }
    }
    // 判断边数是否等于 n -1 
    if (edges != n - 1) {
        return false;
    }
    // 判断入度数是否都是 <=1,这里统计入度数 > 1的节点个数
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (inDegree[i] > 1) {
            count++;
        }
    }
    // 不该存在入度数 >1 的节点,如果存在,返回false
    if (count > 0) {
        return false;
    }
    // 判断是否存在环,此时根节点只能存在一个
    return unionFind.sum == 1;
}

最终代码如下:

public class Test1361 {
    public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) {
        int[] inDegree = new int[n];
        UnionFind unionFind = new UnionFind(n);
        int edges = 0;
        for (int i = 0; i < n; i++) {
            int left = leftChild[i];
            int right = rightChild[i];
            if (left != -1) {
                inDegree[left]++;
                unionFind.union(i, left);
                edges++;
            }
            if (right != -1) {
                inDegree[right]++;
                unionFind.union(i, right);
                edges++;
            }
        }
        // 判断边数是否相等
        if (edges != n - 1) {
            return false;
        }
        // 判断入度数是否都是 <=1
        int count = 0;
        for (int i = 0; i < n; i++) {
            if (inDegree[i] > 1) {
                count++;
            }
        }
        if (count > 0) {
            return false;
        }
        // 判断是否存在环
        return unionFind.sum == 1;
    }

    class UnionFind {
        private int[] parent;
        private int[] rank;
        private int sum;

        public UnionFind(int n) {
            rank = new int[n];
            parent = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
            }
            sum = n;
        }

        public int find(int x) {
            while (x != parent[x]) {
                x = parent[x];
            }
            return x;
        }

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            // 如果两个元素的根节点一致,不需要合并
            if (rootX == rootY) {
                return;
            }
            // 如果根节点 rootX 的深度 > rootY。
            if (rank[rootX] > rank[rootY]) {
                // 那么将以rootY作为根节点的集合加入到rootX对应的集合当中
                rank[rootX] += rank[rootY];
                // 同时改变rootY的根节点,指向rootX。
                parent[rootY] = rootX;
            } else {
                // 反之
                rank[rootY] += rank[rootX];
                parent[rootX] = rootY;
            }
            sum--;
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++:stl:stack、queue、priority_queuej介绍及模拟实现和容量适配器deque介绍

本文主要介绍c中stl的栈、队列和优先级队列并对其模拟实现&#xff0c;对deque进行一定介绍并在栈和队列的模拟实现中使用。 目录 一、stack的介绍和使用 1.stack的介绍 2.stack的使用 3.stack的模拟实现 二、queue的介绍和使用 1.queue的介绍 2.queue的使用 3.queue的…

C++篮球俱乐部管理系统

一、 本系统的设计 篮球俱乐部管理系统是一个用于管理篮球俱乐部日常运营和球队管理的软件系统。它提供了一套功能齐全的工具&#xff0c;帮助篮球俱乐部进行会员管理、训练计划安排、比赛管理、场地预订以及财务记录等方面的工作。 该管理系统的主要特点和功能包括&#xff…

fcpx插件:82种复古电影胶卷框架和效果mFilm Matte

无论您是在制作音乐剪辑、私人假期视频还是大型广告活动&#xff0c;这个专业的插件都将帮助您为您的镜头赋予真正的电影角色。 复古效果在任何视频中都能立即识别出来&#xff0c;增添了感伤的复古氛围&#xff0c;并使镜头更具说服力。使用 mFilm Matte 轻松实现这些特征&…

通过人才测评系统,对程序员岗位进行招聘测评

一、 程序员的基本工作内容 1、 负责项目组内的代码维护和更新迭代&#xff0c;保证研发效率&#xff0c;对于运营产品提出的需求应积极沟通并实现。 2、 规范相关开发文档等相关资料&#xff0c;对于有变更的代码和功能需求&#xff0c;要对开发文档做出相应的变更。 3、 作为…

从0开始深入理解并发、线程与等待通知机制(上)含大厂面试题

目录 一&#xff0c;基础概念 进程与线程 进程&#xff08;就是一代代码的执行程序&#xff0c;程序的实例&#xff09; 线程 大厂面试题&#xff1a;进程间的通信 CPU 核心数和线程数的关系 上下文切换&#xff08;Context switch&#xff09; 并行和并发 二&#xff0c;认识…

SwiftUI 4.0:两种方式实现子视图导航功能

0. 概览 从 SwiftUI 4.0 开始&#xff0c;觉悟了的苹果毅然抛弃了已“药石无效”的 NavigationView&#xff0c;改为使用全新的 NavigationStack 视图。 诚然&#xff0c;NavigationStack 从先进性来说比 NavigationView 有不小的提升&#xff0c;若要如数家珍得单开洋洋洒洒…

Leetcode---114双周赛

题目列表 2869. 收集元素的最少操作次数 2870. 使数组为空的最少操作次数 2871. 将数组分割成最多数目的子数组 2872. 可以被 K 整除连通块的最大数目 一、收集元素的最小操作次数 直接模拟&#xff0c;倒序遍历即可&#xff0c;代码如下 class Solution { public:int mi…

ROS(5)PX4仿真安装及运行

1、配置&#xff0c;提升下载速度 启动 $ cd clash-for-linux$ sudo bash start.sh$ source /etc/profile.d/clash.sh$ proxy_on 关闭 $ cd clash-for-linux$ sudo bash shutdown.sh$ proxy_off 2、安装PX4开源无人机 git clone https://github.com/PX4/PX4-Autopilot.git…

全栈开发笔记1:首个项目的收获

本文为编程导航实战项目学习笔记。 文章目录 7.跨域问题解决 2023.10.26.项目部署 2023.10.15.统一处理返回值 2023.10.14.开发注册和用户管理 2023.09303.开发登陆注册接口 2023.09.172.数据库设计1.前后端初始化 2023.9.16 7.跨域问题解决 2023.10.2 三种方式&#xff1a; …

ps插件:alpaca增效工具 (完美替代AI创成式填充) 2.8.1 中文版

Alpaca是一个Photoshop插件&#xff0c;提供了多种功能&#xff0c;帮助用户更高效地进行图像处理和设计。可以进行模型训练并无缝地融入图像中。同时还提供文本到图像的生成、图像到图像的变化、涂色、放大、深度图创建等功能&#xff0c;极大地提升了设计和艺术创作的效率和创…

Go,从命名开始!Go的关键字和标识符全列表手册和代码示例!

目录 一、Go的关键字列表和分类介绍关键字在Go中的定位语言的基石简洁与高效可扩展性和灵活性 关键字分类声明各种代码元素组合类型的字面表示基本流程控制语法协程和延迟函数调用 二、Go的关键字全代码示例关键字全代码示例 三、Go的标识符定义基础定义特殊规定关键字与标识符…

【Aseprite像素画】如何取巧做到各种画面效果(小工具的各种技巧)

文章目录 参考链接&#xff1a;具体如下1、水中倒影2、参考图片3多个帧添加动画物品4多个帧删除动画物品5六毛钱受击效果6添加标签7导出特定标志的gif图8忽略标志帧&#xff0c;然后播放9轮廓线10多个图层轮廓线11洋葱皮12替换多个不同帧的色块簇13连接细胞14快速连续删除15冻结…

战火使命兑换码最新,战火使命礼包码

战火使命手游是一款二次元卡牌游戏&#xff0c;玩家可以通过使用兑换码来获取礼包奖励。如果你还不知道如何获取兑换码&#xff0c;下面为你提供最新的礼包码合集。 关注【娱乐天梯】&#xff0c;获取内部福利号 战火使命兑换码最新&#xff1a; 1、兑换码&#xff1a;ZHSM0421…

安装matplotlib_

安装pip 安装matplotlib 安装完毕 导入出现bug......

C++算法 —— 动态规划(10)二维费用背包

文章目录 1、动规思路简介2、一和零3、盈利计划 背包问题需要读者先明白动态规划是什么&#xff0c;理解动规的思路&#xff0c;并不能给刚接触动规的人学习。所以最好是看了之前的动规博客&#xff0c;以及两个背包博客&#xff0c;或者你本人就已经懂得动规了。 1、动规思路简…

弧度、圆弧上的点、圆的半径(r)、弧长(s)之间的关系

要计算弧度和圆弧上的点&#xff0c;需要知道以下几个要素&#xff1a; 圆的半径&#xff08;r&#xff09;&#xff1a;即圆的中心到圆周上任意一点的距离。 弧长&#xff08;s&#xff09;&#xff1a;从圆周上的一个点到另一个点所经过的弧长。 弧度&#xff08;θ&#x…

为什么Spring不建议使用基于字段的依赖注入

在我们通过IDEA编写Spring的代码的时候&#xff0c;假如我们编写了如下代码&#xff1a; IDEA会给我们一个warning警告&#xff1a; 翻阅官方文档&#xff1b;我们会发现&#xff1a; 大意就是强制依赖使用构造器注入&#xff0c;可选依赖使用setter注入那么这是为什么呢&am…

App测试时常用的adb命令你都掌握了哪些呢?

adb 全称为 Android Debug Bridge&#xff08;Android 调试桥&#xff09;&#xff0c;是 Android SDK 中提供的用于管理 Android 模拟器或真机的工具。 adb 是一种功能强大的命令行工具&#xff0c;可让 PC 端与 Android 设备进行通信。adb 命令可执行各种设备操作&#xff0…

【服务器】在 Linux CLI 下安装 Anaconda

【服务器】在 Linux CLI 下安装 Anaconda 1 系统环境2 下载安装包3 安装 1 系统环境 查看系统信息 cat /etc/os-release2. 查看架构 uname -a # output # Linux localhost.localdomain 4.18.0-193.28.1.el8_2.x86_64 #1 SMP Thu Oct 22 00:20:22 UTC 2020 x86_64 x86_64 x86…

4.Tensors For Beginners-Vector Definition

在上一节&#xff0c;已经了解了前向和后向转换。 什么是向量&#xff1f; 定义1&#xff1a;向量是一个数字列表 这很简洁&#xff0c;也通俗易懂。 现有两个向量&#xff1a; 如果要把这两个向量给加起来&#xff0c;只需把对应位置的元素(组件)给加起来。 而要缩放向量&…