算法体系-11 第十一节:二叉树基本算法(上)

一 两链表相交

1.1 题目描述

给定两个可能有环也可能无环的单链表,头节点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的 第一个节点。如果不相交,返回null

【要求】

如果两个链表长度之和为N,时间复杂度请达到O(N),额外空间复杂度 请达到O(1)。

1.2 判断一个单链表是否有环

情况 :假如一个单链表,给你一个头节点,如果有环的话返回第一个入环的节点,如果无环的话返回null?

1.2.1 方案一 容器的办法 Set<>集合

1.2.1.1 假如链表无环,走到null的时候,在hashset里面都没有找到重复的

假如链表是有环的,遍历链表的判断当前链表每个节点,判断当前节点是否在hashset里面,如果在就说明有环,如果不在将该节点放入set里面,如果遍历到最后一个null后m都没找到有在hash里面的节点说明无环

1.2.1.2 代码
//快慢指针public boolean hasCycle(ListNode head) {if (head == null) {return false;}ListNode slow = head;ListNode fast = head.next;while (slow != fast) {if (fast == null || fast.next == null) {return false;}slow = slow.next;fast = fast.next.next;}return true;}
}
/*** 通过Set集合记录值的方式,如果有重复的数据,就代表有环* @param node* @return*/private boolean hasCycle2(Node node) {Set<Node> nodeSet = new HashSet<>();//此字段仅用来记录遍历次数int traverseCount = 0;while (node != null) {if (nodeSet.contains(node)) {Log.d(TAG, "hasCycle2==>有环...traverseCount="+traverseCount);return true;}traverseCount ++;Log.d(TAG, "hasCycle2==>traverseCount="+traverseCount);nodeSet.add(node);node = node.next;}Log.d(TAG, "hasCycle2==>无环");return false;}
1.2.1.3 总结

链表的环可能有很多,但单链表只有一个next指针,不会出现分叉的情况

1.2.2 使用快慢指针遍历链表

思路:使用快慢指针遍历链表,快指针一旦走到

null,则该单链表一定无环(快指针一次走两步),如果存在环的话,快指针与慢指针一定会在环上相遇。

当快慢指针相遇时,让快指针重新指向初始节点;慢指针原地不变;两个指针都每次走一步,一定会在链表的入环节点相遇

1.2.2.1 分析

情况一 如果快指针走到null了说明无环

如下情况图解找到相遇的点,但不是相交的入口节点,再做图二的解析,当相遇的时候,快指针去到链表的头,慢指针留在原地继续走,这个时候快慢指针都只走一步,这样再次往前走的话他两一定会在入口节点相遇,这个相遇的点就为入口的交点

1.2.2.2 代码
public static class Node {public int value;  public Node next;    public Node(int data) {this.value = data;   }
}
// 找到链表第一个入环节点,如果无环,返回nullpublic static Node getLoopNode(Node head) {if (head == null || head.next == null || head.next.next == null) {return null;}// n1 慢  n2 快Node slow = head.next; // n1 -> slowNode fast = head.next.next; // n2 -> fastwhile (slow != fast) {if (fast.next == null || fast.next.next == null) {return null;}fast = fast.next.next;slow = slow.next;}// slow fast  相遇fast = head; // n2 -> walk again from headwhile (slow != fast) {slow = slow.next;fast = fast.next;}return slow;}

1.2.2.3 总结

快慢指针找链表入环的节点

1、找到相遇点

2、快指针去到链表头再都分别往前走就能找到

1.3 本题分析

情况一 两个链表都无环的情况-存在相交,

情况二 如果两个链表一个无环,一个有环-不存在相交,因为相交后只存在一个next,只有一个有环需要两个next

情况三 两个都有环 的情况,这个环在相交节点后成一个环

情况一

情况二

情况三两个链表有环的情况

1.3.1 情况一 两个链表都无环的情况-存在相交,

1.3.1.1 hashset

先判断两个链表都没环的情况,先通过上面的方法判断每个链表是否有环,再利用hashset,先将一个链表放入hashset里面,再遍历宁一个链表是否有节点在haseset里面

1.3.1.2 二不使用hashset

分析

先都让两个无环的链表走到最后,看是最后一个节点的内存地址是否相等,不相等一定不相交,end1==end2那么他们是一定相交的,end1和end2是他们相交的最后一个节点,要求的是第一个相交的节点,让长的一个走先他多出来的节点,再让短的和他们一起走,当有相等的时候那么这个点就是他们相交的第一个节点;

代码

// 如果两个链表都无环,返回第一个相交节点,如果不想交,返回nullpublic static Node noLoop(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;}Node cur1 = head1;Node cur2 = head2;int n = 0;while (cur1.next != null) {n++;cur1 = cur1.next;}while (cur2.next != null) {n--;cur2 = cur2.next;}//判断是否相交if (cur1 != cur2) {return null;}// n  :  链表1长度减去链表2长度的值cur1 = n > 0 ? head1 : head2; // 谁长,谁的头变成cur1cur2 = cur1 == head1 ? head2 : head1; // 谁短,谁的头变成cur2n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;}

1.3.2 情况二

分析 如果两个链表一个无环,一个有环-不存在相交,因为相交后只存在一个next,要一个有环需要两个next

1.3.3 情况三

情况三 两个都有环 的情况,这个环在相交节点后成一个环

当loop1 和loop2相等的化就是情况三的第二种

当loop1 和loop2不相等的化就是情况三的第一种和第三种

1.3.3.1 loop1 == loop2

当loop1 和loop2相等的化、话就是情况三的第二种,求第一个交点

分析 当loop1 和loop2终止点时,就和情况一中的求无环链表的第一个交点一样

1.3.3.2 loop1 != loop2

当loop1 和loop2不相等的化就是情况三的第一种和第二种

分析 loop1环节点开始,我转一圈的过程中如果越到loop2说明是情况三, loop1 和 loop2都是他两的相交节点

没有越到说明是情况1,没有相交节点情况1返回null

1.3.3 代码
// 两个有环链表,返回第一个相交节点,如果不想交返回nullpublic static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {Node cur1 = null;Node cur2 = null;if (loop1 == loop2) {cur1 = head1;cur2 = head2;int n = 0;while (cur1 != loop1) {n++;cur1 = cur1.next;}while (cur2 != loop2) {n--;cur2 = cur2.next;}cur1 = n > 0 ? head1 : head2;cur2 = cur1 == head1 ? head2 : head1;n = Math.abs(n);while (n != 0) {n--;cur1 = cur1.next;}while (cur1 != cur2) {cur1 = cur1.next;cur2 = cur2.next;}return cur1;} else {cur1 = loop1.next;while (cur1 != loop1) {if (cur1 == loop2) {return loop1;}cur1 = cur1.next;}return null;}}
1.3.4 主函数调用
public static Node getIntersectNode(Node head1, Node head2) {if (head1 == null || head2 == null) {return null;    }Node loop1 = getLoopNode(head1);   Node loop2 = getLoopNode(head2);   if (loop1 == null && loop2 == null) {return noLoop(head1, head2);   }if (loop1 != null && loop2 != null) {return bothLoop(head1, loop1, head2, loop2);   }return null;}

二 二叉树的先序、中序、后序遍历

2.1 递归实现

2.1.1 前中后遍历的讲解

先序 中序 后序 都可以由以下函数改出来,把打印放在第一次,第二次,第三次就是对应的前中后遍历;

递归序

充分理解递归点过程,根据递归的实现原理,        

2.1.2 代码

package class10;public class Code02_RecursiveTraversalBT {public static class Node {public int value;public Node left;public Node right;public Node(int v) {value = v;}}public static void f(Node head) {if (head == null) {return;}// 1f(head.left);// 2f(head.right);// 3}// 先序打印所有节点public static void pre(Node head) {if (head == null) {return;}System.out.println(head.value);pre(head.left);pre(head.right);}public static void in(Node head) {if (head == null) {return;}in(head.left);System.out.println(head.value);in(head.right);}public static void pos(Node head) {if (head == null) {return;}pos(head.left);pos(head.right);System.out.println(head.value);}public static void main(String[] args) {Node head = new Node(1);head.left = new Node(2);head.right = new Node(3);head.left.left = new Node(4);head.left.right = new Node(5);head.right.left = new Node(6);head.right.right = new Node(7);pre(head);System.out.println("========");in(head);System.out.println("========");pos(head);System.out.println("========");}}

2.2 非递归实现-

2.2.1 前序遍历

2.2.1.1 分析
2.2.1.2 代码
public static class Node {public int value;public Node left;public Node right;public Node(int v) {value = v;}}public static void pre(Node head) {System.out.print("pre-order: ");if (head != null) {Stack<Node> stack = new Stack<Node>();stack.add(head);while (!stack.isEmpty()) {head = stack.pop();System.out.print(head.value + " ");if (head.right != null) {stack.push(head.right);}if (head.left != null) {stack.push(head.left);}}}System.out.println();}

2.2.2 中序遍历


2.2.2.1 分析

2.2.2.2 代码
public static void in(Node cur) {System.out.print("in-order: ");if (cur != null) {Stack<Node> stack = new Stack<Node>();//cur == null 还需要继续保证往下,通过!stack.isEmpty()while (!stack.isEmpty() || cur != null) {if (cur != null) {stack.push(cur);cur = cur.left;//1、假如上面的最后一个节点 cur = d.left;} else {//2、cur == null ,弹出  cur = stack.pop(); 为d,//3、找cur = cur.right;还是空,还是来到这个循环,//4、弹出的就是b了,cur = stack.pop();为e了继续往下走//5、e的左右都为空再弹出的就是a了cur = stack.pop();System.out.print(cur.value + " ");cur = cur.right;}}}System.out.println();}

2.2.3 后续遍历

2.2.3.1 在先序遍历的基础上进行修改, 先改出一个头右左去压栈(压栈的时候先左再右,弹出来就对了),从新栈出来就是左右头就是后续遍历

先在压栈头左右基础上改出一个压栈为头右左的形式,弹出的时候不立马打印,而是先压入一个栈里面最后再弹出就是后续遍历

左右头

2.2.3.2 代码
public static void pos1(Node head) {System.out.print("pos-order: ");if (head != null) {Stack<Node> s1 = new Stack<Node>();Stack<Node> s2 = new Stack<Node>();s1.push(head);while (!s1.isEmpty()) {head = s1.pop(); // 头 右 左s2.push(head);if (head.left != null) {s1.push(head.left);}if (head.right != null) {s1.push(head.right);}}// 左 右 头while (!s2.isEmpty()) {System.out.print(s2.pop().value + " ");}}System.out.println();}

扩展见代码 用一个栈来实现

三 附加题 X 祖先节点 交集 后边再看

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

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

相关文章

静电无处不在:揭秘液晶显示屏静电防护的“大师级“策略

静电&#xff0c;仿佛是电子产品制造过程中的隐形杀手&#xff0c;尤其对于液晶显示屏等精密电子元器件的影响更是不可小觑。然而&#xff0c;面对这一挑战&#xff0c;有些制造商采取了一系列超越寻常的静电防护措施。今天&#xff0c;我们将揭开他们的"大师级"策略…

利用Android studio 查看模拟器中数据文件

打开Android studio &#xff0c;然后按照下图选择 然后会在右侧打开一个这样子的管理弹窗 找到 data/data/your project file 你的缓存跟下载的文件就都在里面了

BigDecimal保留两位小数失败问题

文章目录 背景问题解决如何测试代码 背景 测试时发现在线swagger测试会自动处理BigDecimal小数点后面的数字&#xff0c;就是有零的会都给你去掉&#xff0c;比如9.000与9.500到最后都会被swagger处理成9跟9.5。使用postman测是最准的&#xff0c;测出来的就是9.000跟9.500。 …

数据库基本内容与安装MySQL数据库

目录 一.数据库基本内容 1.数据 &#xff08;1&#xff09;描述事物的符号记录 &#xff08;2&#xff09;包括数字&#xff0c;文字、图形、图像、声音、档案记录等 &#xff08;3&#xff09;以“记录”形式按统一的格式进行存储 2.表 &#xff08;1&#xff09;将不同…

【Linux】基础 IO(动静态库)-- 详解

一、前言 为什么要使用别人的代码&#xff1f; 主要是为了提高程序开发的效率和程序的健壮性。 当别人把功能都实现了&#xff0c;然后我们再基于别人的代码去做二次开发&#xff0c;那么效率当然就提高了。其次&#xff0c;这里基于的别人当然不是随便找的一个人&#xff0c;…

[Qt学习笔记]Qt鼠标事件mouseMoveEvent实时获取图像的坐标和像素值

目录 1、介绍2、效果展示3、实现过程3.1 图像的加载和显示3.2 设置鼠标跟踪事件激活3.3 实现代码 4、源码展示 1、介绍 上一篇介绍了使用OpenCV的setMouseCallback回调函数实现获取鼠标点击点的图像坐标和像素值&#xff0c;本篇使用鼠标事件mouseMoveEvent函数来实现实时获取…

OPPO 后端二面,凉凉。。。

美众议院通过 TikTok 法案 之前我们讲了 老美要求字节跳动在 165 天内剥离短视频应用 TikTok&#xff0c;当时的最新进度是 TikTok 给 1.7 亿美国用户发弹窗&#xff0c;发动用户群众给国会打电话进行抗议。 但显然这点力度的抗议并不会造成什么实质影响。 昨晚&#xff0c;美国…

精读《useRef 与 createRef 的区别》

1 引言 useRef 是常用的 API&#xff0c;但还有一个 createRef 的 API&#xff0c;你知道他们的区别吗&#xff1f;通过 React.useRef and React.createRef: The Difference 这篇文章&#xff0c;你可以了解到何时该使用它们。 2 概述 其实原文就阐述了这样一个事实&#xf…

【EDSR】《Enhanced Deep Residual Networks for Single Image Super-Resolution》

CVPR workshops-2017 首尔大学 code&#xff1a; https://github.com/limbee/NTIRE2017/tree/masterhttps://github.com/sanghyun-son/EDSR-PyTorch 文章目录 1 Background and Motivation2 Related Work3 Advantages / Contributions4 Method4.1 Residual blocks4.2 Single…

盘点国内IP地址服务的功能及提供商

随着互联网的快速发展和普及&#xff0c;IP地址服务提供商在中国市场扮演着越来越重要的角色。这些代理软件提供商不仅为用户提供稳定的网络连接&#xff0c;还可以帮助用户实现IP地址切换、绕过地理限制等功能。虎观代理接下来将详解国内IP地址服务的主要功能&#xff0c;并对…

字符串函数---(1)

字符函数 文章目录 前言1.strlen 的使用和模拟实现2.strcpy 的使用和模拟实现3. strcat 的使用和模拟实现4. strcmp 的使用和模拟实现 前言 上一篇我们学习了字符函数&#xff0c;下来我们学习常见的字符串函数 1.strlen 的使用和模拟实现 size_t strlen(const char *str) 字…

DDOS攻击防御介绍

DDOS&#xff1a;分布式拒绝服务攻击 瞬间收到大量数据 总带宽是有限的 合法用户访问的时候&#xff0c;被非法方法流量占据 无法溯源 流量清洗&#xff1a;AntiDdos 边界&#xff0c;旁挂的 备用域名&#xff0c;ip更换 机房会提供解决方案 解决不了问题&#xff0c;就干…

【真实体会】花几百块买ChatGPT4.0账号一年值得吗?

GPT4.0使用体验及价值 性能提升: GPT4比GPT3.5在内容质量和数量上有显著提高&#xff0c;使得知乎等平台的收益增加。 功能丰富: GPT4支持文本、图片、文件问答&#xff0c;而GPT3.5仅支持文本。GPT4内置多种专业工具&#xff08;GPTS&#xff09;&#xff0c;如设计师LOGO的A…

Android Studio实现内容丰富的安卓视频管理平台

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号081 1. 开发环境 android stuido 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.本地视频 3.视频播放 4.收藏功能 5.网路视频 6.个人中心 7.我的收藏 8.浏览历史 3.系…

Redis高阶使用消息队列分布式锁排行榜等

一、前言 在大多数传统的web系统中&#xff0c;使用Redis一般都是作为缓存使用&#xff0c;在大数据查询时作为缓解性能的一种解决方案。博主的的系统中使用Redis也主要使用到缓存的作用&#xff0c;还有做了注册中心&#xff0c;分布式事务。其他的强大的功能&#xff0c;没有…

【哈希表】算法例题

目录 五、哈希表 39. 赎金信 ① 40. 同构字符串 ① 41. 单词规律 ① 42. 有效的字母异位词 ① 43. 字母异位词分组 ② 44. 两数之和 ① 45. 快乐数 ① 46. 存在重复元素 ① 47. 最长连续序列 ② 五、哈希表 39. 赎金信 ① 给你两个字符串&#xff1a;ransomNote 和 m…

Linux课程_____网络管理

一、查看接口信息 1. ifconfig 查看所有活动网络接口的信息 ifconfig -a 查看所有网络接口信息 ifconfig 直接加网络接口 查看指定网络接口信息 1.1查看指定接口IP [rootlocalhost ~]# ip addr show ens160 1.2设置网络接口的IP地址 # ifconfig eth0 192.168.152.133 …

全国各省市县统计年鉴/中国环境统计年鉴/中国工业企业数据库/中国专利数据库/污染排放数据库

统计年鉴是指以统计图表和分析说明为主&#xff0c;通过高度密集的统计数据来全面、系统、连续地记录年度经济、社会等各方面发展情况的大型工具书来获取统计数据资料。 统计年鉴是进行各项经济、社会研究的必要前提。而借助于统计年鉴&#xff0c;则是研究者常用的途径。目前国…

DC-DC 变换集成电路芯片MC34063A测试参数介绍

MC34063A 为一单片 DC-DC 变换集成电路&#xff0c;内含温度补偿的参考电压源&#xff08;1.25V&#xff09;、比较器、能有效限制电流及控制工作周期的振荡器&#xff0c;驱动器及大电流输出开关管等。外配少量元件&#xff0c;就能组成升压、降压及电压反转型 DC-DC 变换器。…

基于springboot+vue的火锅店管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…