题目地址:https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/

题目描述

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:

在节点 c1 开始相交。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

注意:

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
  • 本题与主站 160 题相同:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

解题方法

本题有两种主要的方法:

  • 使用额外空间(栈、HashSet)
  • 不使用额外空间

方法一:栈

第一个公共节点,相当于是从后往前找第一个不公共的。

所以可以用栈来做:使用两个栈,把两个链表的所有节点分别入栈。然后同时出栈,出栈的时候刚开始都是公共的节点,直到找到最后一个公共的节点。

python 代码:

# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
stack1 = []
stack2 = []
while pHead1:
stack1.append(pHead1)
pHead1 = pHead1.next
while pHead2:
stack2.append(pHead2)
pHead2 = pHead2.next
pre = None
while stack1 and stack2 and stack1[-1] == stack2[-1]:
pre = stack1.pop()
stack2.pop()
return pre

方法二:HashSet

也可以用 HashSet 保存一条链表的所有节点。然后对另一条链表进行遍历,判断节点是否在 HashSet 中,如果是的话,就说明是公共节点。

C++ 代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
unordered_set<ListNode*> visited;
ListNode* move = headA;
while (move) {
visited.insert(move);
move = move->next;
}
move = headB;
while (move) {
if (visited.count(move))
return move;
move = move->next;
}
return nullptr;
}
};

方法三:不使用额外空间

不使用额外空间的方法,巧妙地使用了数学方法。

假设:

  • 链表 A 前面的非公共部分长度是 m
  • 链表 B 前面的非公共部分长度是 n
  • 链表 A 和 B 的公共部分长度是 x

使用两个指针 moveA 和 moveB,同时从链表 A 和 链表 B 的开头向后遍历。

假设链表 A 更短,即 m < n,那么当 moveA 已经遍历到链表 A 结尾的时候,则把它移动到链表 B 的开头继续遍历;当 moveB 已经遍历到链表 B 结尾的时候,则把它移动到链表 A 的开头继续遍历。

这样能保证两个指针相交的时候,即为第一个公共节点。

证明如下:

当两个指针相交的时候,分为 3 种情况——

  1. m == n ,即非公共部分长度相等,那么当两个链表还没有遍历完成一次的时候,两个指针就会相遇。
  2. m < n,那么 moveA 会把链表 A 先遍历结束(moveA 走了 m + x 长度,此时 moveB 还有 (n + x) - (m + x) = n - m 的长度到达链表尾部),把 moveA 移动到链表 B 的开头;当 moveB 把链表 B 遍历结束时(此时 moveB 和 moveA 都走了 n - m 的长度),moveB 移动到链表 A 的开头。当两个指针再往前走 m 步,那么恰好 moveA 处于链表 B 的 n - m + m = n 的位置,moveB 处于链表 A 的 m 的位置。所以两者会相遇在第一个公共节点上。
  3. m > n,同上。

代码里面需要注意的地方是需要当 moveA 和 moveB 都是空的时候(而不是 moveA->next 为空),才移动到另外一条链表的头部。否则,当两条链表没有交点的时候,会陷入死循环。

C++ 代码如下:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* move1 = headA;
ListNode* move2 = headB;
while (move1 != move2) {
move1 = move1 ? move1->next : headB;
move2 = move2 ? move2->next : headA;
}
return move1;
}
};

日期

2018 年 3 月 22 日 —— 睡了个懒觉,感觉好幸福。。
2021 年 7 月 22 日 —— 昨天提了离职

【剑指Offer】52. 两个链表的第一个公共节点 解题报告(Python)的更多相关文章

  1. 剑指 Offer 52. 两个链表的第一个公共节点 + 链表 + 第一个公共结点 + 双指针

    剑指 Offer 52. 两个链表的第一个公共节点 Offer_52 题目详情 题解分析 可以使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结 ...

  2. 力扣 - 剑指 Offer 52. 两个链表的第一个公共节点

    题目 剑指 Offer 52. 两个链表的第一个公共节点 思路1(栈) 若两个链表相遇,则从它开始相遇的地方到链表末尾应该都是相同的,那么我们可以将两个链表分别放入两个栈中,然后依次循环比较两个栈顶的 ...

  3. 每日一题 - 剑指 Offer 52. 两个链表的第一个公共节点

    题目信息 时间: 2019-07-03 题目链接:Leetcode tag: 单链表 难易程度:简单 题目描述: 输入两个链表,找出它们的第一个公共节点. 示例: A: a1 -> a2 \ - ...

  4. 剑指 Offer 52. 两个链表的第一个公共节点

    题目链接 题目描述: 我的题解: 方法一:双指针法 思路分析: 声明两个指针p1,p2 分别指向链表A.链表B. 然后分别同时逐结点遍历 当 p1 到达链表 headA 的末尾时,重新定位到链表 he ...

  5. [LeetCode]剑指 Offer 52. 两个链表的第一个公共节点

    题解 nodeA走一个链表A(A独有+公共),再走B独有的长度, nodeB走一个链表B(B独有+公共),再走A独有的长度. 结果:两者相遇点即为交点:若没有交点,两者都走到null,会返回null. ...

  6. 【Java】 剑指offer(52) 两个链表的第一个公共结点

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入两个链表,找出它们的第一个公共结点. 思路 蛮力法:遍历第一个 ...

  7. 剑指offer——55两个链表的第一个公共节点

    题目描述 输入两个链表,找出它们的第一个公共结点. 题解: 分别遍历两个链表到链尾,并计算其长度,若最后一个节点相同,则存在公共节点 然后让长链表指针从头先移动长度差个节点,然后两个链表指针一起移动, ...

  8. 【剑指offer】两个链表的第一个公共结点,C++实现

    原创文章,转载请注明出处! 博客文章索引地址 # 题目 #举例 如果两个单向链表有公共的节点,那么这两个链表从第一个公共结点开始,之后所有结点都是重合的,不可能再出现分叉.拓扑结构如下图所示: # 思 ...

  9. Go语言实现:【剑指offer】两个链表的第一个公共结点

    该题目来源于牛客网<剑指offer>专题. 输入两个链表,找出它们的第一个公共结点. Go语言实现: //长度长的先走个长度差,然后ab一起比较后面结点 //长度一样,公共结点可能在首结点 ...

随机推荐

  1. C 语言中求中间数时候防止溢出方法

    当使用二分法时候,注意 mid = left + (right - left) / 2; 这句代码,可以防止溢出!!,千万不能写成 mid = (left + right) / 2 这样写的话,当数字 ...

  2. 日常Javaweb 2021/11/19

    Javaweb Dao层: //连接数据库,实现增查功能 package dao; import java.sql.Connection; import java.sql.DriverManager; ...

  3. Spring同一个类中的注解方法调用AOP失效问题总结

    public interface XxxService { // a -> b void a(); void b(); } @Slf4j public class XxxServiceImpl ...

  4. oracle异常处理——ORA-01000:超出打开游标最大数

    oracle异常处理--ORA-01000:超出打开游标最大数https://www.cnblogs.com/zhaosj/p/4309352.htmlhttps://blog.csdn.net/u0 ...

  5. spring boot项目创建与使用

    概述 spring boot通常使用maven创建,重点在于pom.xml配置,有了pom.xml配置,可以先创建一个空的maven项目,然后从maven下载相关jar包. spring boot d ...

  6. 【Spring Framework】Spring注解设置Bean的初始化、销毁方法的方式

    bean的生命周期:创建---初始化---销毁. Spring中声明的Bean的初始化和销毁方法有3种方式: @Bean的注解的initMethod.DestroyMethod属性 bean实现Ini ...

  7. .net 5 开发部署B/S程序。

    现在.net 6 已经出来了,visualStudio 2022也发行预览版了. 自 .net5 发布,.net core 与.net framework 已经走向统一.确实越来越好用了. 现在.ne ...

  8. java多线程5:线程间的通信

    在多线程系统中,彼此之间的通信协作非常重要,下面来聊聊线程间通信的几种方式. wait/notify 想像一个场景,A.B两个线程操作一个共享List对象,A对List进行add操作,B线程等待Lis ...

  9. Mongodb单点部署

    目录 一.依赖和环境 二.部署 三.启动和测试 一.依赖和环境 centos7.2,4核cpu, 8G内存 100G硬盘 版本:3.4.7社区版本 端口:27017 数据目录:/usr/local/m ...

  10. 『学了就忘』Linux系统管理 — 82、Linux中进程的查看(ps命令)

    目录 1.ps命令介绍 2.ps aux命令示例 3.ps -le命令示例 4.pstree命令 1.ps命令介绍 ps命令是用来静态显示系统中进程的命令. 不过这个命令有些特殊,它部分命令的选项前不 ...