(简单)剑指Offer || 056. 二叉搜索树中两个节点的和 Java

news2024/11/24 3:14:29

在这里插入图片描述

方法一:深度优先搜索+哈希表

使用深度优先搜索的方式遍历整棵树,用哈希表记录遍历过的节点的值

对于一个值为x的节点,检查哈希表中是否存在k-x即可。如果存在对应的元素,那么我们就可以在该树上找到两个节点的和为k;否则,将x放入到哈希表中

如果遍历完整棵树都不存在对应的元素,那么该树上不存在两个和为k的节点

import java.util.HashSet;
import java.util.Set;

class Solution {

    Set<Integer> set = new HashSet<>();

    public boolean findTarget(TreeNode root, int k) {
        if (root == null) {
            return false;
        }
        if (set.contains(k - root.val)) {
            return true;
        }
        set.add(root.val);
        return findTarget(root.left, k) || findTarget(root.right, k);
    }
}

复杂度分析:

  • 时间复杂度:O(n),其中n为二叉树的大小。需要遍历整棵树一次。
  • 空间复杂度:O(n),其中n为二叉树的大小。主要为哈希表的开销,最坏情况下需要将每个节点加入哈希表一次。
    在这里插入图片描述
    方法二:广度优先搜索 + 哈希表

使用广度优先搜索的方式遍历整棵树,用哈希表记录遍历过的节点值

首先,创建一个哈希表和一个队列,将根节点加入队列中,然后执行以下步骤:(层序遍历)

  1. 从队列中取出队头,假设其值为x
  2. 检查哈希表中是否存在k-x,如果存在返回true
  3. 否则,将该节点的值加入哈希表,将该节点的左右非空节点加入队尾
  4. 重复以上步骤,直到队列为空
  5. 如果队列为空,说明树上不存在两个和为k的节点,返回false
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Set<Integer> set = new HashSet<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (set.contains(k - node.val)) {
                return true;
            }
            set.add(node.val);
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        return false;
    }
}

复杂度分析:

  • 时间复杂度:O(n),其中n为二叉搜索树的大小。需要遍历整棵树一次。
  • 空间复杂度:O(n),其中n为二叉搜索树的大小。主要为哈希表和队列的开销,最坏情况下需要将每个节点加入哈希表和队列各一次。

在这里插入图片描述

方法三:深度优先搜索+中序遍历+双指针

二叉搜索树的中序遍历是升序排列的,可以将该二叉搜索树的中序遍历的结果记录下来,得到一个升序数组。

具体地,使用两个指针分别指向数组的头尾,当两个指针指向的元素之和小于k时,让左指针右移;当两个指针指向的元素之和大于k时,让右指针左移;当两个指针指向的元素之和等于k时,返回true

最终,当左指针和右指针重合时,树上不存在两个和为k的节点,返回false

import java.util.ArrayList;
import java.util.List;

class Solution {

    List<Integer> list = new ArrayList<>();

    public boolean findTarget(TreeNode root, int k) {
        inorder(root);
        int n = list.size();
        int left = 0;
        int right = n - 1;
        while (left < right && right < n) {
            int val = list.get(left) + list.get(right);
            if (val < k) {
                left++;
            } else if (val > k) {
                right--;
            } else {
                return true;
            }
        }
        return false;
    }

    public void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        inorder(root.left);
        list.add(root.val);
        inorder(root.right);
    }
}

复杂度分析:

  • 时间复杂度:O(n),其中n为二叉搜索树的大小。我们需要遍历这棵树一次,并对得到的升序数组使用双指针遍历。
  • 空间复杂度:O(n),其中n为二叉搜索树的大小。主要为升序数组的开销。

在这里插入图片描述
方法四:迭代 + 中序遍历 + 双指针

在方法三中,是在中序遍历得到的数组上进行双指针,这样需要消耗O(n)的空间,实际上可以将双指针的移动理解为在树上的遍历过程的一次移动。因为递归方法较难控制移动过程,因此可以使用迭代的方式进行遍历。

具体地,对于每一个指针新建一个栈。初始,让左指针移动到树的最左端点,并将路径保存在栈中,接下来依据栈来O(1)地计算出左指针的下一个位置。右指针也是同理。

计算下一个位置时,首先将位于栈顶的当前节点从栈中弹出,此时,首先判断当前节点是否存在右子节点,如果存在,那么将右子节点的最左子树加入到栈中;否则就完成了当前层的遍历,无需进一步修改栈的内容,直接回溯到上一层即可。

import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        TreeNode left = root;
        TreeNode right = root;
        Stack<TreeNode> leftStack = new Stack<>();
        Stack<TreeNode> rightStack = new Stack<>();

        leftStack.push(left);
        while (left.left != null) {
            leftStack.push(left.left);
            left = left.left;
        }

        rightStack.push(right);
        while (right.right != null) {
            rightStack.push(right.right);
            right = right.right;
        }

        while (left != right) {
            int val = left.val + right.val;
            if (val > k) {
                right = getRight(rightStack);
            } else if (val < k) {
                left = getLeft(leftStack);
            } else {
                return true;
            }
        }
        return false;
    }

    private TreeNode getLeft(Stack<TreeNode> leftStack) {
        TreeNode root = leftStack.pop();
        TreeNode node = root.right;
        while (node != null) {
            leftStack.push(node);
            node = node.left;
        }
        return root;
    }

    private TreeNode getRight(Stack<TreeNode> rightStack) {
        TreeNode root = rightStack.pop();
        TreeNode node = root.left;
        while (node != null) {
            rightStack.push(node);
            node = node.right;
        }
        return root;
    }

}

复杂度分析:

  • 时间复杂度:O(n),其中n为二叉搜索树的大小。在双指针的过程中,实际上遍历了整棵树一次。
  • 空间复杂度:O(n),其中n为二叉搜索树的大小。主要为栈的开销,最坏情况下二叉搜索树为一条链,需要O(n)的栈空间。

在这里插入图片描述

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

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

相关文章

Idea 修改默认 Maven 为自己的

每次我们打开新项目时,都要去配置一遍 maven,很麻烦,其实可以去修改 idea 里面默认的 maven 配置,这样后面不管是打开新项目还是老项目,就都是用的自己的 maven 了. 1.文件->新项目设置->新项目的设置 File->Other Settings -> Settings for New Project 2.然后和…

【Unity开发必备】100多个 Unity 学习网址 资源 收藏整理大全【持续更新】

Unity 相关网站整理大全 众所周知&#xff0c;工欲善其事必先利其器&#xff0c;有一个好的工具可以让我们事半功倍&#xff0c;有一个好用的网站更是如此&#xff01; 但是好用的网站真的太多了&#xff0c;收藏夹都满满的(但是几乎没打开用过&#x1f601;)。 所以本文是对…

eclipse : sun.misc.BASE64Encoder找不到jar包的解决方法

sun.misc.BASE64Encoder找不到jar包 比较好的解决办法 按顺序依次操作&#xff1a; Windows -> Preferences -> Java -> Compiler -> Errors/Warnings。再按照顺序依次&#xff1a; Deprecated and trstricted API -> Forbidden reference (access rules): -&g…

量子力学的实验验证:双缝实验和贝尔不等式

亲爱的读者&#xff0c; 欢迎回到我们的量子力学系列文章。在前几篇文章中&#xff0c;我们介绍了量子力学的起源、基本概念&#xff0c;以及叠加态、超级定位和量子纠缠等奇特现象。今天&#xff0c;我们将深入探讨量子力学的实验验证&#xff0c;重点介绍双缝实验和贝尔不等…

Android自定义圆环进度条/刻度仪表盘(单环单点带进度动画)

效果图: 1.自定义SleepDashBoardView /*** 睡眠刻度仪表盘*/ public class SleepDashBoardView extends View {private static final float START_ANGLE 135f;private static final float MAX_ANGLE 270f;private float progress 0;private float centerX;private float ce…

ValueError: check_hostname requires server_hostname怎么解决?

背景: 想使用pip安装某一个包。结果报错如上图绿框所示。 解决方法&#xff1a; 把代理&#xff08;梯子&#xff09;关掉就行了。

数据库应用:MySQL事务、存储引擎

目录 一、理论 1.事务 2.MySQL 存储引擎 二、实验 1.事务隔离级别 2.事务控制语句 三、总结 一、理论 1.事务 &#xff08;1&#xff09;概念 ① 事务是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个整体一起向系…

XUbuntu22.04之解决ThindPad P15V风扇狂转的问题(一百八十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

深度学习标量、向量、矩阵、张量之间的区别与联系

文章目录 前言1、张量**注意**&#xff1a; 2、**标量** (scalar)&#xff1a;0阶的张量&#xff0c;0个轴&#xff0c;一个单独的数(整数或实数)&#xff1b;3、**向量**(vector)&#xff1a;1阶的张量&#xff0c;也叫矢量&#xff0c;1个轴&#xff0c;一个数组&#xff1b;…

elasticsearch学习入门+实战

学习链接1 基础概念 官网学习&#xff1a;地址 基本命令 PS&#xff1a;使用Apifox测试 查询所有索引库 添加索引库 添加时&#xff0c;加入分词器 添加时&#xff0c;加入记录属性值 查询获取索引库 删除索引库 添加文档 必须要在添加文档值的时候用【_doc】&a…

如何建立统一的自动化测试平台?

前面的文章中我们为大家介绍了中通科技自动化测试当时正在面临的一些困境。第一个是自动化测试框架太多&#xff0c;测试工程师在选择框架和脚本语言的时候很难统一&#xff0c;脚本编写门槛高。第二个是运行脚本的平台不统一&#xff0c;脚本运行时不够稳定。第三个是不同的Je…

TDengine数据建模

文章目录 1 引言2 数据建模3 数据建模的步骤4 创建库5 创建超级表实例 1 引言 工业互联网中有大量的时序数据需要存储和处理&#xff0c;tdengine是一个开源的、国产的、云原生时序数据库&#xff0c;tdengine不是基于其他第三方开源软件高级封装&#xff0c;是涛思数据完全自…

Java如何避免“重复代码”

一 前言 软件工程师和码农最大的区别就是平时写代码时习惯问题&#xff0c;码农很喜欢写重复代码而软件工程师会利用各种技巧去干掉重复的冗余代码。 业务同学抱怨业务开发没有技术含量&#xff0c;用不到设计模式、Java 高级特性、OOP&#xff0c;平时写代码都在堆 CRUD&…

2022-2023年项目总结

1.健康监护仪&#xff08;WPF-用时两周&#xff09; 通讯协议比较复杂&#xff0c;但展示要求不高&#xff0c;时间都花在了后台代码上&#xff0c;不过调试过程比较顺利&#xff0c;总体用时不长&#xff0c;下图&#xff1a;假数据演示 2.AI内窥镜&#xff08;WPF-用时2月&a…

Windows10 PDF文件删不掉 解决办法

在使用Windows10系统时&#xff0c;有时会遇到文件删不掉的情况&#xff0c;本文提供一种删除文件方法&#xff0c;在自己计算机尝试成功。 适用环境&#xff1a;Windows10下名字太长的PDF文件。 原因&#xff1a;文件名超过255个字符长度&#xff0c;导致windows10 系统无法…

REMB-接收端最大接收码率评估

draft-alvestrand-rmcat-remb-03 接收方带宽估计的RTCP消息 REMB_fanyamin的博客-CSDN博客 webrtc中的码率控制_webrtc设置码率_linux_vae的博客-CSDN博客 参考&#xff1a; Walter: WebRTC 拥塞控制之 REMB - 接收方带宽估计 - 简书 WebRTC基于TransportCC和Trendline Fil…

VMware的两种备份方式

1、VMware的系统备份方式 ① 快照备份 ② 克隆备份 2、快照备份 快照&#xff1a;又称还原点&#xff0c;就是保存在拍快照时候的系统的状态&#xff08;包含了所有的内容&#xff09;&#xff0c;在后期的时候随时可以恢复。 ☆ 拍摄快照 第一步&#xff1a;启动Linux的…

升级至iOS17公测版系统后如何降级?iOS 17 Beta降级详细教程

苹果最近发布iOS 17首个公测版&#xff0c;许多果粉都迫不及待地进行了更新。但是不少小伙伴升级iOS 17后iPhone遇到了一些问题&#xff0c;例如APP闪退、吃内存、耗电快等。Bug太多导致体验很差&#xff0c;想要降级到iOS 16系统。 升级iOS 17beta后悔了&#xff1f;其实只要苹…

蓝牙资讯|三星申请多项智能戒指商标,可与头显设备联动

三星向欧洲监管机构提交了多项智能戒指相关的商标申请。国外科技媒体 patentlyapple 报道称&#xff0c;三星计划让智能戒指作为 XR 头显设备的延伸&#xff0c;以进一步和苹果的 Vision Pro 头显竞争。 智能戒指&#xff1b; 可穿戴计算机本质上的智能手环、智能项链、智能眼…

Web_php_include

代码审计 进入环境&#xff0c;根据题目的提示&#xff0c;本题考察文件包含漏洞 <?php show_source(__FILE__); echo $_GET[hello]; $page$_GET[page]; while (strstr($page, "php://")) {$pagestr_replace("php://", "", $page); } incl…