数据结构和算法-04二叉树-04

news2024/12/26 23:14:41
  1. 广度优先的实现
  2. 力扣中常见的二叉树相关问题及基本解决方案
    tips: 在解决问题时,先确保问题能解决,再去考虑效率,这是解题的关键,切不可为追求效率而变成了技巧性解答。

广度优先

广度优先(层序遍历)遍历的方式是按层次从上到下,从左到右的逐层访问。

[36, 21, 56, 8, 23, 38,72]

image-20241205134000624

public void levelTraversal(TreeNode root) {
    Deque<TreeNode> queue = new ArrayDeque<>();
    if (root == null) return;
    queue.offer(root);

    while (!queue.isEmpty()) {
        TreeNode peek = queue.pop();
        System.out.println(peek.val);
        if (peek.left != null) {
            queue.offer(peek.left);
        }
        if (peek.right != null) {
            queue.offer(peek.right);
        }
    }
}

力扣问题

  1. 102. 二叉树的层序遍历 - 力扣(LeetCode)
  2. 107. 二叉树的层序遍历 II - 力扣(LeetCode)

二叉树经典例题

计算二叉树的深度

问题

[LCR 175] LCR 175. 计算二叉树的深度 - 力扣(LeetCode)

问题描述

某公司架构以二叉树形式记录,请返回该公司的层级数。

示例 1:

img
输入:root = [1, 2, 2, 3, null, null, 5, 4, null, null, 4]
输出: 4
解释: 上面示例中的二叉树的最大深度是 4,沿着路径 1 -> 2 -> 3 -> 41 -> 2 -> 5 -> 4 到达叶节点的最长路径上有 4 个节点。

解决方案

image-20241204153607653

参考实现

class Solution {
    public int calculateDepth(TreeNode root) {
        if(root == null) return 0;
        return Math.max(calculateDepth(root.left) , calculateDepth(root.right))+1;
    }
}

将有序数组转换为二叉搜索树

问题

108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

问题描述

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵

平衡二叉搜索树。

示例 1:

img

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 2:

img

输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3][3,1] 都是高度平衡二叉搜索树。

解决方案

有序数组拆半放入二叉搜索树。

  • 左边部分放入搜索树左侧
  • 右边部分放入搜索树右侧
image-20241205152303793

参考实现

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        int mid = nums.length / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(Arrays.copyOfRange(nums, 0, mid));
        root.right = sortedArrayToBST(Arrays.copyOfRange(nums, mid + 1, nums.length));
        return root;
    }
}

寻找二叉搜索树中的目标节点

题目

[LCR174] LCR 174. 寻找二叉搜索树中的目标节点 - 力扣(LeetCode)

题目描述

某公司组织架构以二叉搜索树形式记录,节点值为处于该职位的员工编号。请返回第 cnt 大的员工编号。

示例 1:

img
输入:root = [7, 3, 9, 1, 5], cnt = 2
       7
      / \
     3   9
    / \
   1   5
输出:7

示例 2:

img
输入: root = [10, 5, 15, 2, 7, null, 20, 1, null, 6, 8], cnt = 4
       10
      / \
     5   15
    / \    \
   2   7    20
  /   / \ 
 1   6   8
输出: 8

解决方案

中序解决排序问题

参考实现

class Solution {
    public int findTargetNode(TreeNode root, int cnt) {
        List<Integer> list = new ArrayList<Integer>();
        inOrder(root,list);
      //  System.out.println(list);
        return list.get(list.size()-cnt);
    }

    private void inOrder(TreeNode root,List<Integer> list){
        if(root ==null){
            return ;
        }
        inOrder(root.left,list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}

计算布尔二叉树的值

题目

[力扣2331] 2331. 计算布尔二叉树的值 - 力扣(LeetCode)

题目描述

给你一棵 完整二叉树 的根,这棵树有以下特征:

  • 叶子节点 要么值为 0 要么值为 1 ,其中 0 表示 False1 表示 True
  • 非叶子节点 要么值为 2 要么值为 3 ,其中 2 表示逻辑或 OR3 表示逻辑与 AND

计算 一个节点的值方式如下:

  • 如果节点是个叶子节点,那么节点的 为它本身,即 True 或者 False
  • 否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算

返回根节点 root 的布尔运算值。

完整二叉树 是每个节点有 0 个或者 2 个孩子的二叉树。

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

示例 1:

img
输入:root = [2,1,3,null,null,0,1]
输出:true
解释:上图展示了计算过程。
AND 与运算节点的值为 False AND True = FalseOR 运算节点的值为 True OR False = True 。
根节点的值为 True ,所以我们返回 true

示例 2:

输入:root = [0]
输出:false
解释:根节点是叶子节点,且值为 false,所以我们返回 false

解决方案

递归根据情况进行分类。

image-20241204164220106

参考实现

class Solution {
    public boolean evaluateTree(TreeNode root) {
        if(root.val ==1) return true;
        else if(root.val == 0) return false;
        else if(root.val ==2) return evaluateTree(root.left) || evaluateTree(root.right);
        else  return evaluateTree(root.left) && evaluateTree(root.right);
    }
}

二叉搜索树的范围和

问题

[力扣938] 938. 二叉搜索树的范围和 - 力扣(LeetCode)

问题描述

给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。

示例 1:

img

输入:root = [10,5,15,3,7,null,18], low = 7, high = 15
输出:32

示例 2:

img

输入:root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10
输出:23

解决方案

从根节点递归到叶节点的过程中,如果小于low,则走右侧(值的范围必须大于等于low)

如果大于high,则走左侧(值的范围必须小于等于high),

如果在范围内[low, high], 则继续遍历其子节点。

参考实现

放入List集合中,按照集合中数据的访问遍历。

class Solution {
    public int rangeSumBST(TreeNode root, int low, int high) {
        List<Integer>  list  = new ArrayList<>();
        inOrder(root, list);
        int sum=0;
        for(int t :  list){
            if(t >=low && t <=high){
                sum+=t;
            }
        }
        return sum;
    }

    private void inOrder(TreeNode root, List<Integer> list){
        if(root == null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }

}

当前递归节点与low和high进行比较

  • root< low : 说明左侧没有合适的值,那么继续递归右侧
  • root > right: 说明右侧没有合适的值,那么继续递归左侧
  • root 在范围之内,则将左侧和右侧的结果相加+ 当前节点的值。
class Solution {
    public int rangeSumBST(TreeNode root, int low, int high) {
        if(root == null) return 0;
        if(root.val < low){
            return rangeSumBST(root.right, low, high);
        }
        if(root.val > high){
            return rangeSumBST(root.left, low, high);
        }

        return rangeSumBST(root.left,low,high)
               + rangeSumBST(root.right,low,high)
               + root.val;
    }
}

二叉搜索树中第K小的元素

题目

230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)

题目描述

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。

示例 1:

img

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

示例 2:

img

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

解决方案

中序遍历存入list集合

找到list中的第k小项

参考实现

class Solution {
    public int kthSmallest(TreeNode root, int k) {
     List<Integer> list = new ArrayList<>();   
     inOrder(root,list);
    return list.get(k-1);
    }

    private void inOrder(TreeNode root,List<Integer> list){
        if(root==null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right,list);
    }
}

二叉搜索树中的中序后继

题目

[力扣LCR053] LCR 053. 二叉搜索树中的中序后继 - 力扣(LeetCode)

题目分析

给定一棵二叉搜索树和其中的一个节点 p ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null

节点 p 的后继是值比 p.val 大的节点中键值最小的节点,即按中序遍历的顺序节点 p 的下一个节点。

示例 1:

img

输入:root = [2,1,3], p = 1
输出:2
解释:这里 1 的中序后继是 2。请注意 p 和返回值都应是 TreeNode 类型。

示例 2:

img

输入:root = [5,3,6,2,4,null,null,1], p = 6
输出:null
解释:因为给出的节点没有中序后继,所以答案就返回 null 了。

解决方案

  1. 中序记录在List集合中,找到p在list中的位置索引,如果索引>=0 || 不是最后一个位置则返回,否则返回null。
  2. 记录上一个节点pre, 当前curr。

参考实现

class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        Stack<TreeNode> stack = new Stack<>();

        TreeNode curr = root;
        TreeNode pre = null;

        while(curr!=null || !stack.isEmpty()){
            while(curr!=null){
                stack.push(curr);
                curr = curr.left;
            }
           curr = stack.pop();
           if(pre == p){
             return   curr;
           }
           pre = curr;
           curr = curr.right;
        }
        return null;
    }
}

两数之和IV-输入二叉搜索树

问题

[力扣653] 653. 两数之和 IV - 输入二叉搜索树 - 力扣(LeetCode)

问题描述

给定一个二叉搜索树 root 和一个目标结果 k,如果二叉搜索树中存在两个元素且它们的和等于给定的目标结果,则返回 true

示例 1:

img

输入: root = [5,3,6,2,4,null,7], k = 9
输出: true

示例 2:

img

输入: root = [5,3,6,2,4,null,7], k = 28
输出: false

解决方案

  1. 将数据存入一个List集合
  2. 问题转换为找到一个集合中的和为K的两个数。

参考实现

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        List<Integer> list = new ArrayList<>();
        final int DEFAULT_VAL = 999;
        inOrder(root, list);

        //System.out.println(list);

        for(int t : list){
            int target = k - t;
            if(map.containsKey(target)){
                return true;
            }
            map.put(t, DEFAULT_VAL);
        }

        return false;
    }

    private void inOrder(TreeNode root, List<Integer> list) {
        if (root == null) return ;
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }
}
class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Map<Integer,Integer> map = new HashMap<>();
        List<TreeNode> stack  = new ArrayList<>();
        TreeNode curr = root;

        while(curr!=null || !stack.isEmpty()){
            while(curr!=null){
                int target= k - curr.val;
                if(map.containsKey(target)){
                    return true;
                }
                map.put(curr.val,999);
                stack.add(curr);
                curr = curr.left;
            }
            curr = stack.remove(stack.size()-1);
            curr = curr.right;
        }
        return false;
    }
}

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

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

相关文章

DMA代码部分

第一个程序的接线图 OLED ShowHexNum(2,1,(uint32_t)&ADC1->DR,8); 这样可以看AD的DR寄存器的的地址(固定的)了 可以跑一下然后和手册对比 先查ADC1的地址 再在外设的总表里面, 查一下DR相对于上面地址的偏移量 所以其地址为4001 244C 研究一下外设寄存器的地址是怎么…

spdlog高性能日志系统

spdlog高性能日志系统 spdlog 是一个快速、简单、功能丰富的 C 日志库&#xff0c;专为现代 C 开发设计。它支持多种日志后端&#xff08;如控制台、文件、syslog 等&#xff09;&#xff0c;并提供灵活的格式化和线程安全的日志输出。 1. 特点 极高的性能&#xff1a;大量的编…

FPGA在线升级 -- Multiboot

简介 本章节主要描述关于如何从Golden Image转换到Multiboot Image程序。 升级方案 Golden Image转换到Multiboot Image的方法主要又两种 1、使用ICAPE2 原语&#xff1b; 2、在XDC文件中加入升级约束命令&#xff1b; 以上两种方案都可以实现在线升级&#xff0c;第一种升级…

守护进程化

目录 一、进程组 二、会话 &#xff08;1&#xff09;什么是会话 &#xff08;2&#xff09;如何创建一个会话 三、守护进程 一、进程组 之前我们学习过进程&#xff0c;其实每一个进程除了有一个进程 ID(PID)之外 还属于一个进程组。进程组是一个或者多个进程的集合&…

QML插件扩展

https://note.youdao.com/ynoteshare/index.html?id294f86c78fb006f1b1b78cc430a20d74&typenote&_time1706510764806

RabbitMQ七种工作模式之 RPC通信模式, 发布确认模式

文章目录 六. RPC(RPC通信模式)客户端服务端 七. Publisher Confirms(发布确认模式)1. Publishing Messages Individually(单独确认)2. Publishing Messages in Batches(批量确认)3. Handling Publisher Confirms Asynchronously(异步确认) 六. RPC(RPC通信模式) 客⼾端发送消息…

ArcGIS字符串补零与去零

我们有时候需要 对属性表中字符串的补零与去零操作 我们下面直接视频教学 下面看视频教学 ArcGIS字符串去零与补零 推荐学习 ArcGIS全系列实战视频教程——9个单一课程组合 ArcGIS10.X入门实战视频教程&#xff08;GIS思维&#xff09; ArcGIS之模型构建器&#xff08;Mod…

前端面试如何出彩

1、原型链和作用域链说不太清&#xff0c;主要表现在寄生组合继承和extends继承的区别和new做了什么。2、推荐我的两篇文章&#xff1a;若川&#xff1a;面试官问&#xff1a;能否模拟实现JS的new操作符、若川&#xff1a;面试官问&#xff1a;JS的继承 3、数组构造函数上有哪些…

大模型应用编排工具Dify之构建专属FQA应用

1.前言 ​ 通过 dify可以基于开源大模型的能力&#xff0c;并结合业务知识库、工具API和自定义代码等构建特定场景、行业的专属大模型应用。本文通过 dify工作室的聊天助手-工作流编排构建了一个基于历史工作日志回答问题的助手&#xff0c;相比原始的大模型答复&#xff0c;通…

前端node环境安装:nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)

需求&#xff1a;在做前端开发的时候&#xff0c;有的时候 这个项目需要 node 14 那个项目需要 node 16&#xff0c;我们也不能卸载 安装 。这岂不是很麻烦。这个时候 就需要 一个工具 来管理我们的 node 版本和 npm 版本。 下面就分享一个 nvm 工具 用来管理 node 版本。 这个…

c基础加堆练习题

1】思维导图&#xff1a; 2】在堆区空间连续申请5个int类型大小空间&#xff0c;用来存放从终端输入的5个学生成绩&#xff0c;然后显示5个学生成绩&#xff0c;再将学生成绩升序排序&#xff0c;排序后&#xff0c;再次显示学生成绩。显示和排序分别用函数完成 要求&#xff…

嵌入式Linux 设备树 GPIO详解 示例分析 三星 NXP RK

GPIO设备树用于在Linux内核中定义与GPIO相关的硬件资源&#xff0c;它使操作系统可以识别、配置和使用GPIO引脚。设备树中通常会指定GPIO控制器的基地址、GPIO引脚的中断配置、时钟和其他相关信息。 目录 RK相关案例代码 NXP相关案例代码 三星相关案例代码 在设备树中&…

【日记】不想随礼欸(926 字)

正文 今天忙了一天。感觉从早上就开始在救火。客户经理迎接检查&#xff0c;要补资料&#xff0c;找我们问这样要那样&#xff0c;我自己的事情几乎完全开展不了。虽说也没什么大事就是了。 晚上行长还让我重装系统…… 难绷。看来这个爹味新行长懂得还挺多。 中午趁着不多的休…

Spring 源码学习(七)——注解后处理器

通过之前对注解式配置的解析&#xff08;Spring 源码学习&#xff08;三&#xff09;—— 注解式配置解析_spring源码学习-CSDN博客&#xff09;可以发现其使用 AnnotationConfigUtils 类的 registerAnnotationConfigProcessors 静态方法对象注解后处理器对象进行注册&#xff…

如何避免缓存击穿?超融合常驻缓存和多存储池方案对比

作者&#xff1a;SmartX 解决方案专家 钟锦锌 很多运维人员都知道&#xff0c;混合存储介质配置可能会带来“缓存击穿”的问题&#xff0c;尤其是大数据分析、数据仓库等需要频繁访问“冷数据”的应用场景&#xff0c;缓存击穿可能会更频繁地出现&#xff0c;影响业务运行。除…

Scala的正则表达式二

验证用户名是否合法 规则 1.长度在6-12之间 2.不能数字开头 3.只能包含数字&#xff0c;大小写字母&#xff0c;下划线def main(args: Array[String]): Unit {val name1 "1admin"//不合法&#xff0c;是数字开头val name2 "admin123"//合法val name3 &quo…

【CKA】Kubernetes(k8s)认证之CKA考题讲解

CKA考题讲解 0.考试101 0.1 kubectl命令⾃动补全 在 bash 中设置当前 shell 的⾃动补全&#xff0c;要先安装 bash-completion 包。 echo "source <(kubectl completion bash)" >> ~/.bashrc还可以在补全时为 kubectl 使⽤⼀个速记别名&#xff1a; al…

导入kotlin

android studio 导入kotlin项目 android studio kotlin教程 或者直接拿一个kt文件进来&#xff0c;在顶部会显示一个config&#xff0c;然后设置version&#xff0c;点击OK就可以了自动导了

《CSS 知识点》大屏卡片布局思路:弹性布局 flex-grow

思路 大屏左右两侧高宽一致&#xff0c;内部卡片可按比例设置&#xff01; 使用弹性布局和属性 flex-grow 设置比例&#xff1b;间隔使用 margin-bottom 设置&#xff0c;最后一个卡片不设置&#xff1b; 效果如图 代码说明 CSS代码 26 - 30&#xff0c;左右两侧设置弹性布…

责任链模式的理解和实践

责任链模式&#xff08;Chain of Responsibility&#xff09;是行为型设计模式之一&#xff0c;它通过将多个对象连成一条链&#xff0c;并沿着这条链传递请求&#xff0c;直到有对象处理它为止。这个模式的主要目的是将请求的发送者和接收者解耦&#xff0c;使请求沿着处理链传…