一、题目

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:



在节点 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) 内存。

二、题解

  • 题解1:哈希表

遍历链表 A 并将每个节点的地址/引用存储在哈希表中。

然后检查链表 B 中的每一个节点是否在哈希表中。若在,则为相交结点。

/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
var s [] *ListNode for headA != nil {
s = append(s, headA)
headA = headA.Next
}
for headB != nil {
for _,v := range(s) {
if v == headB {
return headB
}
}
headB = headB.Next
}
return nil
}
  • 题解2:链表拼接法

当链表 A 走到尾部的 null 时,转到链表 B 的头节点继续走;

当链表 B 走到尾部的 null 时,转到链表 A 的头节点继续走;

若两链表相交,则 A 和 B 一定相遇。



如上图:初始化 pA = headA, pB = headB,开始遍历。

pA会先到达链表尾,当pA到达末尾时,重置pA为headB;同样的,当pB到达末尾时,重置pB为headA。当pA与pB相遇时,必然就是两个链表的交点。

为什么要这样处理?因为对 pA 而言,走过的路程为 a+c+b,对 pB 而言,为 b+c+a,显然 a+c+b = b+c+a,这就是该算法的核心原理。

即使两个链表没有相交点,仍然可以统一处理,因为这种情况意味着相交点就是 null,也就是上图中的公共部分c没有了,从而递推式变成了 pA: a+bpB: b+a,同样是成立的。

时间复杂度:O(m+n),空间复杂度:O(1)。

/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
if (headA == nil || headB == nil) {
return nil
}
pA, pB := headA, headB
for pA != pB {
if pA == nil {
pA = headB
} else {
pA = pA.Next
}
if pB == nil {
pB = headA
} else {
pB = pB.Next
}
}
return pA
}
  • 题解3:消除链表长度差

两个单链表,有公共结点,则必然尾部公用;

分别找出链表 1 和链表 2 的长度,长的链表减去短的链表得出一个 n 值;

长的链表先走 n 步,两个链表再同时移动,则两个链表相交点就是第一个公共结点。

时间复杂度:O(n),空间复杂度:O(1)。

/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
if headA == nil || headB == nil {
return nil
}
lenA := getLen(headA)
lenB := getLen(headB) //计算链表长度差 n,长的先移动 n 步
if (lenA > lenB) {// 链表A比链表B长,A先移动
for i := 0; i < lenA - lenB; i++ {
headA = headA.Next
}
} else {// 链表B比链表A长,B先移动
for i := 0; i < lenB - lenA; i++ {
headB = headB.Next
}
} for headA != nil {
if headA == headB {
return headA
}
headA = headA.Next
headB = headB.Next
}
return nil;
} //获取链表长度
func getLen(head *ListNode) int {
var len int
for head != nil {
len++
head = head.Next
}
return len
}

后记

这道题也是面试题中经常遇到的“两个链表的第一个公共节点”。虽然难度是“简单”,但对我来说一点也不简单。看评论和题解涨了很多姿势。

而且,一开始用的是 PHP,可怎么都通不过,不得不用 Go 重写了一遍,倒是很快通过了。

附上 PHP 版本:

  • 题解1 PHP版本
class ListNode {
public $val = 0;
public $next = null;
function __construct($val) {
$this->val = $val;
}
} /**
* @param ListNode $headA
* @param ListNode $headB
* @return ListNode
*/
function getIntersectionNode($headA, $headB) {
$hashMap = [];
while ($headA) {
$hashMap[] = $headA;
$headA = $headA->next;
}
while ($headB) {
if (in_array($headB, $hashMap)) {
return $headB;
}
$headB = $headB->next;
}
return null;
}
  • 题解2 PHP版本
function getIntersectionNode($headA, $headB) {
if ($headA == null || $headB == null) {
return null;
} $pA = $headA;
$pB = $headB;
while ($pA != $pB) {
$pA = $pA == null ? $headB : $pA->next;
$pB = $pB == null ? $headA : $pB->next;
}
return $pA;
}
  • 题解3 PHP版本
function getIntersectionNode($headA, $headB) {
$lenA = getListLength($headA);
$lenB = getListLength($headB); $diffLen = $lenA > $lenB ? $lenA - $lenB : $lenB - $lenA;
$headLong = $lenA > $lenB ? $headA : $headB;
$headShort = $lenA > $lenB ? $headB : $headA; //先在长链表上走几步,再同时在两个链表上遍历
for ($i = 0; $i < $diffLen; $i++) {
$headLong = $headLong->next;
}
while ($headLong != $headShort) {
$headLong = $headLong->next;
$headShort = $headShort->next;
}
return $headLong;
} /**
* 获取链表的长度
*/
function getListLength($head)
{
$length = 0;
$current = $head;
while ($current != null) {
$length++;
$current = $current->next;
}
return $length;
}

LeetCode#160-Intersection of Two Linked Lists-相交链表的更多相关文章

  1. 【LeetCode】Intersection of Two Linked Lists(相交链表)

    这道题是LeetCode里的第160道题. 题目讲的: 编写一个程序,找到两个单链表相交的起始节点. 如下面的两个链表: 在节点 c1 开始相交. 示例 1: 输入:intersectVal = 8, ...

  2. 160 Intersection of Two Linked Lists 相交链表

    编写一个程序,找到两个单链表相交的起始节点.例如,下面的两个链表:A:           a1 → a2                            ↘                   ...

  3. Leetcode 160 Intersection of Two Linked Lists 单向链表

    找出链表的交点, 如图所示的c1, 如果没有相交返回null. A:             a1 → a2                               ↘               ...

  4. [LeetCode] 160. Intersection of Two Linked Lists 解题思路

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  5. [LeetCode]160.Intersection of Two Linked Lists(2个链表的公共节点)

    Intersection of Two Linked Lists Write a program to find the node at which the intersection of two s ...

  6. [LeetCode] 160. Intersection of Two Linked Lists 求两个链表的交集

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  7. LeetCode 160. Intersection of Two Linked Lists (两个链表的交点)

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  8. Leetcode 160. Intersection of two linked lists

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  9. Java for LeetCode 160 Intersection of Two Linked Lists

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

  10. ✡ leetcode 160. Intersection of Two Linked Lists 求两个链表的起始重复位置 --------- java

    Write a program to find the node at which the intersection of two singly linked lists begins. For ex ...

随机推荐

  1. Contest 154

    2019-09-16 17:22:28 总体感受:这次比赛的模版题也太多了吧,两条模版题没有想出来.总的来说,还是自己的刷题量还是严重的不够. 注意点: 1)提升刷题量和覆盖率非常重要: 2)在碰到大 ...

  2. [离散化+树状数组]CodeForces - 652D Nested Segments

    Nested Segments time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  3. 如何使用 electron 屏幕或摄像头录制并保存到本地

    思路分析 通过 electron desktopCapturer 和 navigator 获取要进行录制的媒体源信息: 使用 MediaRecorder 对视频流进行录制: 将 MediaRecord ...

  4. mysql系列--sql实现原理

    count(*) MyISAM 引擎把⼀个表的总⾏数存在了磁盘上,因此执⾏ count(*) 的时候会直接返回这个数,效率很⾼:但是加了条件则不能快速返回⽽ InnoDB 引擎就麻烦了,它执⾏ cou ...

  5. win 7 系统过期处理办法

    超级尴尬,刚装的win7 系统居然过期了.下次再也不装盗版了,吼吼吼 处理方法就是下载oem7F7 软件安装,不用再怎么操作就好了. 就是这么简单,并不用像网上那样找什么激活码.

  6. OpenCV-Python 模板匹配 | 三十一

    目标 在本章中,您将学习 使用模板匹配在图像中查找对象 你将看到以下功能:cv.matchTemplate(),cv.minMaxLoc() 理论 模板匹配是一种用于在较大图像中搜索和查找模板图像位置 ...

  7. KDD 2019放榜!录取率仅14%,强调可重现性

    [导读]KDD 2019录取结果终于放榜了,今年Research和ADS两个 track共评审论文1900篇,其中Research track的录取率只有14%.今年也是KDD第一次采用双盲评审政策, ...

  8. Ali_Cloud++:阿里云服务器防火墙相关命令

    systemctl start firewalld ##启动Firewall systemctl stop firewalld ##关闭Firewall systemctl restart firew ...

  9. 树莓派 Raspberry PI基础

    树莓派 Raspberry PI基础 官网网址:https://www.raspberrypi.org 下载地址:https://www.raspberrypi.org/downloads/ 官方系统 ...

  10. 1033 To Fill or Not to Fill (25分)(贪心)

    With highways available, driving a car from Hangzhou to any other city is easy. But since the tank c ...