二叉树 + 技巧

news2024/12/26 10:46:46
题目难度备注
2471. 逐层排序二叉树所需的最少操作数目1635BFS + 置换环 + 离散化
2641. 二叉树的堂兄弟节点 II1677BFS

文章目录

  • 周赛二叉树问题
    • [2471. 逐层排序二叉树所需的最少操作数目](https://leetcode.cn/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-level/)
    • [2641. 二叉树的堂兄弟节点 II](https://leetcode.cn/problems/cousins-in-binary-tree-ii/)

周赛二叉树问题

2471. 逐层排序二叉树所需的最少操作数目

难度中等27

给你一个 值互不相同 的二叉树的根节点 root

在一步操作中,你可以选择 同一层 上任意两个节点,交换这两个节点的值。

返回每一层按 严格递增顺序 排序所需的最少操作数目。

节点的 层数 是该节点和根节点之间的路径的边数。

示例 1 :

img

输入:root = [1,4,3,7,6,8,5,null,null,null,null,9,null,10]
输出:3
解释:
- 交换 4 和 3 。第 2 层变为 [3,4] 。
- 交换 7 和 5 。第 3 层变为 [5,6,8,7] 。
- 交换 8 和 7 。第 3 层变为 [5,6,7,8] 。
共计用了 3 步操作,所以返回 3 。
可以证明 3 是需要的最少操作数目。

示例 2 :

img

输入:root = [1,3,2,7,6,5,4]
输出:3
解释:
- 交换 3 和 2 。第 2 层变为 [2,3] 。 
- 交换 7 和 4 。第 3 层变为 [4,6,5,7] 。 
- 交换 6 和 5 。第 3 层变为 [4,5,6,7] 。
共计用了 3 步操作,所以返回 3 。 
可以证明 3 是需要的最少操作数目。

提示:

  • 树中节点的数目在范围 [1, 105]
  • 1 <= Node.val <= 105
  • 树中的所有值 互不相同

题解:https://leetcode.cn/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-level/solution/by-liu-wan-qing-zjlj/

以计算使得 [7, 6, 8, 5] 严格递增需要的最小交换次数为例,画出置换环算法图解如下:

在这里插入图片描述

经典问题:置换环求解数组排序需要的最小交换次数

置换环的思想为 : 对每个节点,将其指向其排序后应该放到的位置,直到首位相接形成了一个环。

具体实现思想:

  • 使用 Map 哈希表记录每个节点值以及其应该放到的位置
  • 从头到尾遍历初始数组,使用 flag[] 数组标记当前元素是否已经参与过(即已经被加入环中),对已经参与过的数组则不再需要遍历。每次成环结束,记录成环个数 loop。
  • 最终最小交换次数为 :数组长度 - 成环个数( nums.size() - loop

置换环算法一般情况代码如下:

// 返回使得 nums 递增需要的最小交换元素次数
public int minChanges(int[] nums){
    int[] copy = Arrays.copyOf(nums, nums.length);
    Arrays.sort(copy); // 排序,获得有序的nums数组copy
    // 离散化:记录元素原本应该出现的位置 i
    HashMap<Integer, Integer> map = new HashMap<>();
    for(int i=0; i<copy.length; i++){
        map.put(copy[i], i);
    }
    boolean[] flag = new boolean[nums.length];  // 用于标记 nums[i] 是否已经被加入环中
    int loop = 0; // 环的个数
    for(int i=0; i<nums.length; i++){
        if(!flag[i]){
            int j = i;
            while(!flag[j]){ // 画环
                int index = map.get(nums[j]); // 当前节点指向的实际存放位置,画环过程
                flag[j] = true; // 将 j 加入环中
                j = index; // 将当前节点移动到环上下个节点
            }
            loop++; // 环数递增
        }
    }
    return nums.length - loop; // 最小交换次数为 : 数组长度 - 环数
}

代码实现

class Solution {
    public int minimumOperations(TreeNode root) {
        int res = 0;
        if(root == null) return res;
        Deque<TreeNode> dq = new ArrayDeque<>();
        dq.add(root);
        while(!dq.isEmpty()){
            List<Integer> levellist = new ArrayList<>();
            int size = dq.size();
            while(size-- > 0){
                TreeNode node = dq.poll();
                levellist.add(node.val);
                if(node.left != null) dq.add(node.left);
                if(node.right != null) dq.add(node.right);
            }
            // 计算该数组排序需要的最小交换次数:置换环
            int loop = 0;
            List<Integer> tmp = new ArrayList<>(levellist);
            Collections.sort(levellist);
            boolean[] flag = new boolean[tmp.size()];
            Map<Integer, Integer> map = new HashMap<>();
            for(int i = 0; i < tmp.size(); i++){
                map.put(levellist.get(i), i);
            }
            for(int i = 0; i < tmp.size(); i++){
                if(!flag[i]){
                    int j = i;
                    while(!flag[j]){
                        int index = map.get(tmp.get(j));
                        flag[j] = true;
                        j = index;
                    }
                    loop++;
                }
            }
            res += (tmp.size() - loop);
        }
        return res;
    }
}

2641. 二叉树的堂兄弟节点 II

难度中等0

给你一棵二叉树的根 root ,请你将每个节点的值替换成该节点的所有 堂兄弟节点值的和

如果两个节点在树中有相同的深度且它们的父节点不同,那么它们互为 堂兄弟

请你返回修改值之后,树的根 root

注意,一个节点的深度指的是从树根节点到这个节点经过的边数。

示例 1:

img

输入:root = [5,4,9,1,10,null,7]
输出:[0,0,0,7,7,null,11]
解释:上图展示了初始的二叉树和修改每个节点的值之后的二叉树。
- 值为 5 的节点没有堂兄弟,所以值修改为 0 。
- 值为 4 的节点没有堂兄弟,所以值修改为 0 。
- 值为 9 的节点没有堂兄弟,所以值修改为 0 。
- 值为 1 的节点有一个堂兄弟,值为 7 ,所以值修改为 7 。
- 值为 10 的节点有一个堂兄弟,值为 7 ,所以值修改为 7 。
- 值为 7 的节点有两个堂兄弟,值分别为 1 和 10 ,所以值修改为 11 。

示例 2:

img

输入:root = [3,1,2]
输出:[0,0,0]
解释:上图展示了初始的二叉树和修改每个节点的值之后的二叉树。
- 值为 3 的节点没有堂兄弟,所以值修改为 0 。
- 值为 1 的节点没有堂兄弟,所以值修改为 0 。
- 值为 2 的节点没有堂兄弟,所以值修改为 0 。

提示:

  • 树中节点数目的范围是 [1, 105]
  • 1 <= Node.val <= 104

BFS遍历

https://leetcode.cn/problems/cousins-in-binary-tree-ii/solution/bfssuan-liang-ci-pythonjavacgo-by-endles-b72a/

站在父节点的视角,去看下一层节点的取值:(站在父节点的位置上解决子节点的问题!!!启发点:对于一个节点 x 来说,它的所有堂兄弟节点值的和,等价于 x 这层的所有节点值之和,减去 x 及其兄弟节点的值之和

BFS层序遍历二叉树,对于每一层:

首先,遍历当前层的每个节点,通过节点的左右儿子,计算下层的节点值之和 nextLevelSum;

然后,再次遍历当前层的每个节点 x,计算 x 的左右儿子的节点值之和 childrenSum,更新 x 的左右儿子的节点值为nextLevelSum - childrenSum

class Solution {
    public TreeNode replaceValueInTree(TreeNode root) {
        root.val = 0;
        // 使用List和临时变量tmp来模拟队列(Deque没有get方法)
        List<TreeNode> q = new ArrayList<>();
        q.add(root);
        while(!q.isEmpty()){
            // 用临时遍历保存本层节点,后面需要计算本层节点x左右儿子的节点值之和
            List<TreeNode> tmp = q;
            q = new ArrayList<>();
            int nextLevelSum = 0; // 下一层的节点之和
            // 获取下层节点和的同时进行BFS操作
            for(TreeNode node : tmp){
                if(node.left != null){
                    q.add(node.left);
                    nextLevelSum += node.left.val;
                }
                if(node.right != null){
                    q.add(node.right);
                    nextLevelSum += node.right.val;
                }
            }
            // 再次遍历,更新下一层的节点值
            for(TreeNode node : tmp){
                int childSum = (node.left != null ? node.left.val : 0) + 
                                (node.right != null ? node.right.val : 0);
                if(node.left != null) node.left.val = nextLevelSum - childSum;
                if(node.right != null) node.right.val = nextLevelSum - childSum;
            }
        }
        return root;
    }
}

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

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

相关文章

【AI绘画】云服务器部署stable-diffusion-webui保姆级教程

1.背景 之前给大家写过Mac苹果笔记本上部署stable-diffusion-webui的教程&#xff0c;知乎链接&#xff1a; 【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程 但是安装过程就花了一天的时间&#xff0c;各种问题处理起来真是苦不堪言。。。而且…

如何解决生产缺料问题?

对于一个生产型企业来说&#xff0c;生产缺料是管理中的疑难问题之一。 生产缺料导致的最直接的危害就有两个&#xff1a; 第一就是不能准时交货&#xff0c;降低企业信用&#xff0c;情况严重可能导致根据合同赔款&#xff0c;甚至丢失客户。 第二个危害就是增加了生产成本…

部署LVS-DR 集群及实验

一、LVS-DR工作原理 LVS-DR&#xff08;Linux Virtual Server Director Server&#xff09;工作模式&#xff0c;是生产环境中最常用的一种工作模式。 #①LVS-DR 模式&#xff0c;Director Server 作为群集的访问入口&#xff0c;不作为网关使用&#xff1b; #②节点 Directo…

ueditor富文本编辑器上传木马图片或木马文件漏洞

漏洞分析&#xff1a; ueditor插件目录一般都自带index.html文件&#xff08;完整demo文件&#xff09;&#xff0c;这个文件原来是用来测试插件功能的&#xff0c;但粗心的程序员们&#xff0c;开发好项目后&#xff0c;都忘记删除这个demo文件了&#xff0c;导致黑客可以很轻…

微服务不是本地部署的最佳选择,不妨试试模块化单体

微服务仅适用于成熟产品 关于从头开始使用微服务&#xff0c;马丁・福勒&#xff08;Martin Fowler&#xff09;总结道&#xff1a; 1. 几乎所有成功的微服务都是从一个过于庞大而不得不拆分的单体应用开始的。 2. 几乎所有从头开始以微服务构建的系统&#xff0c;最后都会因…

win11安装双系统ubuntu20.04指导

目录 一、制作U盘启动盘二、硬盘分区2.1方法2.2分区过程 三、安装系统3.1进入U盘启动3.2安装ubuntu3.3设置启动项 四、更新软件五、遇到的问题5.1不能连接WIFI 电脑型号&#xff1a;联想拯救者Y7000P 2023 无线网卡型号&#xff1a;WIFI 6E AX211 160MHz 系统版本&#xff1a;w…

借助尾号限行 API 实现限行规则应用的设计思路分析

引言 尾号限行是指根据车牌号的末尾数字&#xff0c;规定某些时段内不能在特定区域行驶&#xff0c;这是城市交通管理的一种措施。尾号限行政策的实施可以缓解城市交通拥堵问题&#xff0c;减少环境污染和交通事故等问题。 尾号限行 API 是一种提供已知所有执行限行政策的城市…

iSulad+Kuasar:管理面资源消耗锐减 99%的新一代统一容器运行时解决方案

随着云计算和容器技术的不断发展&#xff0c;容器引擎和容器运行时已经成为了云原生时代的基石&#xff0c;它们负责了容器生命周期的管理以及容器运行过程中环境的创建和资源的配置。openEuler 社区基于容器引擎项目 iSulad[1]在解决容器运行效率、安全性以及隔离性等问题上进…

DVWD-Command Injection Low/Medium/High低中高级别

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 Command Injection 一、Low级别二、Medium级别三、High级别 命令注入这关是一个Ping测试功…

《港联证券》半导体复苏预期“抢跑”产业现实 细分市场缓慢回温

虽然说没有一个冬季不可逾越&#xff0c;但本轮“抢跑”的半导体复苏预期&#xff0c;不得不继续面对工业缓慢复苏的实际。 自2022年下半年以来&#xff0c;资本商场上半导体复苏接棒“缺芯”成为关注焦点&#xff0c;部分半导体职业个股迅速收复跌幅&#xff0c;刷新阶段高点&…

Apache ActiveMQ 远程代码执行漏洞 (CVE-2016-3088)复现

当前漏洞环境部署在vulhub,当前验证环境为vulhub靶场&#xff08;所有实验均为虚拟环境&#xff09; 实验环境&#xff1a;攻击机----kali 靶机&#xff1a;centos7 1、进入环境cd activemq/CVE-2016-3088/&#xff08;靶机&#xff09; 2、启动环境&#xff1a;docker-compos…

设备健康管理软件如何帮助企业优化设备维保计划?

基于AI和工业互联网技术的新型设备管理系统&#xff0c;可以通过实时监测设备运行状态、预测潜在故障、提供预防性维护建议等方式&#xff0c;实现设备管理的数字化和智能化。该类设备管理系统的核心功能一般包括设备状态监测、故障预测、预防性维护、故障知识库管理等&#xf…

Java字节码指令

Java代码运行的过程是Java源码->字节码文件(.class)->运行结果。 Java编译器将Java源文件&#xff08;.java&#xff09;转换成字节码文件(.class)&#xff0c;类加载器将字节码文件加载进内存&#xff0c;然后进行字节码校验&#xff0c;最后Java解释器翻译成机器码。 …

第六届中国软件开源创新大赛——飞桨赛题新鲜出炉,速来pick!

最近想要充个电&#x1f50b; 飞桨邀你开启开源贡献之旅 寻找那个最“会”的你 顶级开源项目、资深研发指导、高阶开发者合作交流&#xff0c;‍‍ Buff 叠满&#xff01; 技能提升、丰富简历、高额奖金&#xff0c; 你还不心动&#xff1f; 赛事简介 中国软件开源创新大赛已成…

聊聊StarRocks向量化执行引擎-过滤操作

聊聊StarRocks向量化执行引擎-过滤操作 StarRocks是开源的新一代极速MPP数据库&#xff0c;采用全面向量化技术&#xff0c;充分利用CPU单核资源&#xff0c;将单核执行性能做到极致。本文&#xff0c;我们聊聊过滤操作是如何利用SIMD指令进行向量化操作。 过滤操作的SIMD向量化…

值得拥有的一篇SpringBoot入门基础指南

目录 一. 创建SpringBoot项目1.1 使用Spring Initializr快速构建项目1.2 手动创建springboot项目 二. SpringBoot入门案例解析2.1 依赖管理特性2.2 starter场景启动器2.3 引导类自动配置 三. REST风格四. 配置文件 一. 创建SpringBoot项目 1.1 使用Spring Initializr快速构建项…

「数据架构」MDM实现失败的主要原因

我经常参与一个组织的MDM程序&#xff0c;当他们在一个失败的项目之后向InfoTrellis请求帮助进行清理&#xff0c;或者开始尝试X&#xff0c;以实现对某些人来说非常困难的目标时。主数据管理实现失败的原因有很多&#xff0c;但是没有一个是由于在这些场景中使用的责备游戏的原…

【Redis】Redis缓存

目录 一、缓存 1、概念 2、作用 3、缺点 二、缓存模型 三、缓存的更新 1、更新策略 2、主动更新的三种模式 1.cache aside pattern 2.read/write through pattern 3.write behind caching pattern 3、线程安全问题 1.缓存删除还是更新缓存 2.先删除缓存后操作数据…

英特尔让谷歌云破解其新的安全芯片并发现多个漏洞

谷歌云和英特尔在24日发布了对英特尔新硬件安全产品 Trust Domain Extensions (TDX)为期九个月的审计结果。 该分析揭示了 10 个已确认的漏洞&#xff0c;其中两个被两家公司的研究人员标记为重要漏洞&#xff0c;以及五个导致主动更改以进一步加强 TDX 防御的发现。 检查和修…

FPGA中有限状态机的状态编码采用格雷码还是独热码?

有限状态机是由寄存器组和组合逻辑构成的硬件时序电路&#xff0c;其状态&#xff08;即由寄存器组的1和0的组合状态所构成的有限个状态&#xff09;只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态&#xff0c;究竟转向哪一状态还是留在原状态不但取决于各个输入…