可视化图解算法: 两个链表的第一个公共节点

news/2025/3/20 11:56:26/文章来源:https://www.cnblogs.com/jiangzhou/p/18782776

1. 题目

描述

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

数据范围:n≤1000
要求:空间复杂度 O(1),时间复杂度 O(n)

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

输入描述:

输入分为是3段,第一段是第一个链表的非公共部分,第二段是第二个链表的非公共部分,第三段是第一个链表和第二个链表的公共部分。 后台会将这3个参数组装为两个链表,并将这两个链表对应的头节点传入到函数FindFirstCommonNode里面,用户得到的输入只有pHead1和pHead2。

返回值描述:

返回传入的pHead1和pHead2的第一个公共结点,后台会打印以该节点为头节点的链表。

示例1

输入:

{1,2,3},{4,5},{6,7}

返回值:

{6,7}

说明:

第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的          

示例2

输入:

{1},{2,3},{}

返回值:

{}

说明:

2个链表没有公共节点 ,返回null,后台打印{}   

2. 解题思路

获取两链表的第一个公共节点可以采用如下步骤完成:

步骤一:定义两个指针变量,分别指向两个链表的头节点。

步骤二:移动两个指针变量。

  • 移动指针变量h1,如果指向节点为空:更改指向到另外一个链表(更改到链表2);
  • 移动指针变量h2,如果指向节点为空:更改指向到另外一个链表(更改到链表1)。

指针变量 h1移动轨迹如下:

指针变量 h2移动轨迹如下:

在此过程h1与h2同时移动,移动的前提条件是:h1!=h2。移动示意图如下所示:

步骤三:返回公共节点。

两指针h1与h2相遇, 即:h1与h2指向相同的节点。如果没有公共节点,则:h1与h2都指向Null。

如果文字描述的不太清楚,你可以参考视频的详细讲解。

  • Python版本:https://www.bilibili.com/cheese/play/ep1370397
  • Java版本:https://www.bilibili.com/cheese/play/ep1366841
  • Golang版本:https://www.bilibili.com/cheese/play/ep1364523

3. 编码实现

3.1 Python编码实现

class ListNode:def __init__(self, x):self.val = x  # 链表的数值域self.next = None  # 链表的指针域# 从链表节点尾部添加节点
def insert_node(node, value):if node is None:print("node is None")return# 创建一个新节点new_node = ListNode(value)cur = node# 找到链表的末尾节点while cur.next is not None:cur = cur.next# 末尾节点的next指针域连接新节点cur.next = new_node# 打印链表(从链表头结点开始打印链表的值)
def print_node(node):cur = node# 遍历每一个节点while cur is not None:print(cur.val, end="\t")cur = cur.next  # 更改指针变量的指向print()#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param pHead1 ListNode类
# @param pHead2 ListNode类
# @return ListNode类
#
class Solution:def FindFirstCommonNode(self, pHead1, pHead2):# write code here# 1. 定义两个指针变量,分别指向两个链表的头节点h1 = pHead1h2 = pHead2# 2. 移动两个指针变量while h1 is not h2:# 2.1 移动指针变量h1,如果指向节点为空:更改指向到另外一个链表(更改到pHead2链表)if h1 is None:h1 = pHead2else:h1 = h1.next# 2.2 移动指针变量h2,如果指向节点为空:更改指向到另外一个链表(更改到pHead1链表)if h2 is None:h2 = pHead1else:h2 = h2.next# 3. 返回公共节点(两指针相遇 即:两链表指向相同的节点。如果没有公共节点,则:两链表都指向None)return h2if __name__ == '__main__':comm_nodes = ListNode(6)comm_nodes.next = ListNode(7)root1 = ListNode(1)root1.next = ListNode(2)root1.next.next = ListNode(3)root1.next.next.next = comm_nodesprint_node(root1)root2 = ListNode(4)root2.next = ListNode(5)root2.next.next = comm_nodesprint_node(root2)s = Solution()node = s.FindFirstCommonNode(root1, root2)print(node.val)print_node(node)print("+++++++++++++++++++++++++++++++++++++++++")head1 = ListNode(1)head2 = ListNode(2)head2.next = ListNode(3)node1 = s.FindFirstCommonNode(head1, head2)print(node1)

3.2 Java编码实现

package LL10;public class Main {//定义链表节点static class ListNode {private int val;  //链表的数值域private ListNode next; //链表的指针域public ListNode(int data) {this.val = data;this.next = null;}}//添加链表节点private static void insertNode(ListNode node, int data) {if (node == null) {return;}//创建一个新节点ListNode newNode = new ListNode(data);ListNode cur = node;//找到链表的末尾节点while (cur.next != null) {cur = cur.next;}//末尾节点的next指针域连接新节点cur.next = newNode;}//打印链表(从头节点开始打印链表的每一个节点)private static void printNode(ListNode node) {ListNode cur = node;//遍历每一个节点while (cur != null) {System.out.print(cur.val + "\t");cur = cur.next; //更改指针变量的指向}System.out.println();}public static class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** @param pHead1 ListNode类* @param pHead2 ListNode类* @return ListNode类*/public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {// write code here// 1. 定义两个指针变量,分别指向两个链表的头节点ListNode h1 = pHead1;ListNode h2 = pHead2;// 2. 移动两个指针变量while (h1 != h2) {// 2.1 移动指针变量h1,如果指向节点为空:更改指向到另外一个链表(更改到pHead2链表)if (h1 == null) {h1 = pHead2;} else {h1 = h1.next;}// 2.2 移动指针变量h2,如果指向节点为空:更改指向到另外一个链表(更改到pHead1链表)if (h2 == null) {h2 = pHead1;} else {h2 = h2.next;}}// 3. 返回公共节点(两指针相遇 即:两链表指向相同的节点。如果没有公共节点,则:两链表都指向null)return h1;}}public static void main(String[] args) {ListNode commNodes = new ListNode(6);commNodes.next = new ListNode(7);ListNode root1 = new ListNode(1);root1.next = new ListNode(2);root1.next.next = new ListNode(3);root1.next.next.next = commNodes;printNode(root1);ListNode root2 = new ListNode(4);root2.next = new ListNode(5);root2.next.next = commNodes;printNode(root2);Solution solution = new Solution();ListNode node = solution.FindFirstCommonNode(root1, root2);System.out.println(node.val);printNode(node);System.out.println("+++++++++++++++++++++++++++++++++++++++++");ListNode head1 = new ListNode(1);ListNode head2 = new ListNode(2);head2.next = new ListNode(3);ListNode node1 = solution.FindFirstCommonNode(head1, head2);System.out.println(node1);}
}

3.3 Golang编码实现

package mainimport "fmt"// ListNode 定义链表节点
type ListNode struct {Val  int       //链表的数值域Next *ListNode //链表的指针域
}/**** @param pHead1 ListNode类* @param pHead2 ListNode类* @return ListNode类*/
func FindFirstCommonNode(pHead1 *ListNode, pHead2 *ListNode) *ListNode {// write code here// 1. 定义两个指针变量,分别指向两个链表的头节点h1 := pHead1h2 := pHead2// 2. 移动两个指针变量for h1 != h2 {// 2.1 移动指针变量h1,如果指向节点为空:更改指向到另外一个链表(更改到pHead2链表)if h1 == nil {h1 = pHead2} else {h1 = h1.Next}// 2.2 移动指针变量h2,如果指向节点为空:更改指向到另外一个链表(更改到pHead1链表)if h2 == nil {h2 = pHead1} else {h2 = h2.Next}}// 3. 返回公共节点(两指针相遇 即:两链表指向相同的节点。如果没有公共节点,则:两链表都指向nil)return h2}
func main() {comNodes := &ListNode{Val: 6}comNodes.Next = &ListNode{Val: 7}root1 := &ListNode{Val: 1}root1.Next = &ListNode{Val: 2}root1.Next.Next = &ListNode{Val: 3}root1.Next.Next.Next = comNodesroot1.Print()root2 := &ListNode{Val: 4}root2.Next = &ListNode{Val: 5}root2.Next.Next = comNodesroot2.Print()node := FindFirstCommonNode(root1, root2)fmt.Println(node.Val)node.Print()fmt.Println("++++++++++++++++++++++++++++++++++++++++++++++")head1 := &ListNode{Val: 1}head2 := &ListNode{Val: 2}head2.Next = &ListNode{Val: 3}node1 := FindFirstCommonNode(head1, head2)fmt.Println(node1)}// Insert 从链表节点尾部添加节点
func (ln *ListNode) Insert(val int) {if ln == nil {return}//创建一个新节点newNode := &ListNode{Val: val}cur := ln//找到链表的末尾节点for cur.Next != nil {cur = cur.Next}//末尾节点的next指针域连接新节点cur.Next = newNode
}// Print 从链表头结点开始打印链表的值
func (ln *ListNode) Print() {if ln == nil {return}cur := ln//遍历每一个节点for cur != nil {fmt.Print(cur.Val, "\t")cur = cur.Next //更改指针变量的指向}fmt.Println()
}

如果上面的代码理解的不是很清楚,你可以参考视频的详细讲解。

  • Python版本:https://www.bilibili.com/cheese/play/ep1370397
  • Java版本:https://www.bilibili.com/cheese/play/ep1366841
  • Golang版本:https://www.bilibili.com/cheese/play/ep1364523

4.小结

获取两链表的第一个公共节点可以采用如下步骤完成:(1)定义两个指针变量,分别指向两个链表的头节点。(2)移动两个指针变量。移动到末尾要注意指向的改变,即原来指向的链表1,现在要指向链表2;(3)返回公共节点。

更多数据结构与算法视频讲解,你可以从以下地址找到:

  • Python编码实现:https://www.bilibili.com/cheese/play/ep1509965
  • Java编码实现:https://www.bilibili.com/cheese/play/ep1510007
  • Golang编码实现:https://www.bilibili.com/cheese/play/ep1509945

对于链表的相关操作,我们总结了一套【可视化+图解】方法,依据此方法来解决链表相关问题,链表操作变得易于理解,写出来的代码可读性高也不容易出错。具体也可以参考视频详细讲解。

今日佳句:纸上得来终觉浅,绝知此事要躬行。

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

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

相关文章

Windows 10 on ARM, version 22H2 ARM64 中文版、英文版下载 (2025 年 3 月更新)

Windows 10 on ARM, version 22H2 ARM64 中文版、英文版下载 (2025 年 3 月更新)Windows 10 on ARM, version 22H2 ARM64 中文版、英文版下载 (2025 年 3 月更新) Windows 10 on ARM, version 22H2 ARM64 (updated Mar 2025) 请访问原文链接:https://sysin.org/blog/windows-1…

河南郑州亚克力代加工厂家资源-代加工-外协加工-委外加工-激光代加工-河南郑州亚克力切割雕刻代加工-芯晨微纳(河南)

在河南省寻找亚克力代加工厂家,可以通过以下渠道和注意事项进行筛选: 一、推荐查找渠道**B2B平台 -百度搜索“河南郑州亚克力代加工厂家”、“激光代加工”、“亚克力加工”等关键词阿里巴巴:搜索“河南亚克力加工”“亚克力定制”等关键词,筛选河南本地厂家(如郑州、洛阳…

PureBasic 6.20 (macOS, Linux, Windows) - 现代的 BASIC 编程语言及 IDE

PureBasic 6.20 (macOS, Linux, Windows) - 现代的 BASIC 编程语言及 IDEPureBasic 6.20 (macOS, Linux, Windows) - 现代的 BASIC 编程语言及 IDE PureBasic is a modern BASIC programming language. 请访问原文链接:https://sysin.org/blog/purebasic/ 查看最新版。原创作品…

GIMP 3.0.0 (Linux, macOS, Windows) 正式版发布 - 免费开源图像编辑器

GIMP 3.0.0 (Linux, macOS, Windows) 正式版发布 - 免费开源图像编辑器GIMP 3.0.0 (Linux, macOS, Windows) 正式版发布 - 免费开源图像编辑器 GNU Image Manipulation Program (GIMP) 请访问原文链接:https://sysin.org/blog/gimp/ 查看最新版。原创作品,转载请保留出处。 作…

WinSCP主机名

连接Wifi的情况下,Ubuntu命令行输入"ifconfig",如图即为主机名当我在使用网线时,打开虚拟机显示的ifconfig却是这样:此时连接WinSCP是行不通的因此只能拔掉网线,在WiFi情况下,重启虚拟机,命令行如下: sudo shutdown -r now 然后再重新接入WinSCP即可。 只要在…

从0到1制作智慧医院,全流程解读

在科技飞速发展的今天,智慧医院已成为医疗行业变革的重要方向。想象一下,患者走进医院,无需繁琐的排队挂号,通过智能导诊系统就能快速找到就诊科室;医生借助大数据和人工智能,能更精准地诊断病情、制定治疗方案;医院管理者通过实时的数据监控,优化资源调配,提升运营效…

Pydantic多态模型:用鉴别器构建类型安全的API接口

title: Pydantic多态模型:用鉴别器构建类型安全的API接口 date: 2025/3/20 updated: 2025/3/20 author: cmdragon excerpt: Pydantic的鉴别器机制通过字段显式声明类型,实现自动化路由,避免了传统多态实现中的手动类型判断。基础鉴别器定义通过字段声明和类型标识,实现自…

固件打包流程

基础知识: SHA-256类型: 哈希函数 用途: 用于生成数据的唯一指纹(哈希值),确保数据的完整性。 特性: 不可逆、快速计算、抗碰撞性。RSA类型: 非对称加密算法 用途: 主要用于加密数据、数字签名和密钥交换。 特性: 使用一对密钥(公钥和私钥),其中公钥用于加密或验证签名,…

C语言入口函数

c语言入口函数必须是main

从数据孤岛到信息互通,多宁生物如何用CRM打破集团型企业的协同难题?

上海多宁生物科技股份有限公司(简称“多宁生物”)是一家一站式生物工艺解决方案提供商,提供生物制药产品从研发到商业化生产的全面解决方案,包括试剂及耗材、仪器设备和服务。公司经营生物工艺解决方案、实验室产品及服务两大业务线,帮助客户实现高效、稳定、质量及成本可…

五分钟带你看懂 NVIDIA 和 AI 的未来

(配图:Photo by BoliviaInteligente on Unsplash)前言:2025 年 3 月 18 日,在美国加州圣何塞举行的 GTC 2025 大会上,NVIDIA CEO 黄仁勋发表了长达两小时的主题演讲,详细介绍了 NVIDIA 的未来路线图。 这场被誉为“AI 超级碗”的盛会,吸引了全球开发者、创新者和行业领导…

初识 WebSocket 协议

什么是 WebSocket WebSocket 是一种网络通信协议,是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 属于应用层协议,它基于 TCP 传输协议,并复用 HTTP 的握手通道。 为什么出现 WebSocket 我们已经拥有了 HTTP 协议,为什么还要搞出一套 WebSocket…