前言
Wassup guys!我是Edison
今天是 LeetCode 上的 leetcode 160. 相交链表
Let’s get it!
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
这道题拆分的话,其实就是两步:
(1)判断两个链表是否相交
(2)然后找出第一个交点
首先要判断链表 A 和 链表 B 是否相交,那怎么判断呢?
1. 思路一
就是用 链表 A 的每一个节点去和 链表 B 依次比较判断,如果有相等,就是相交,第一个相等就是相交;反之,不相交
但是这种方法需要那 A 里面的每一个节点去和 B 里面的 N 个节点进行比较,如果 A 有 M 个节点,那么时间复杂度就是 O ( M ∗ N ) O(M*N) O(M∗N)。
注意:这里比较的不是节点里面的 值,比较的是 当前节点存放的下一个节点的地址。
2. 思路二
A链表 找到 尾节点,B链表 也找到 尾节点。
当 尾节点 的地址相同时,就是 相交。
这种方法的时间复杂度为: O ( M + N ) O(M+N) O(M+N)。
既然能判断链表是否相交了,那么如何找到交点呢?
也很简单,直接说方法:
(1)求出 A链表 的长度 La,再求出 B链表 的长度 Lb;
(2)如果 A链表 比 B链表 长,那么 A链表 先走 La - Lb 步;
(2)当 A链表 走了 差距步 以后,再让 A链表 和 B链表 再一起走,第一个 地址 相等的就是交点。
注意:
如果 B链表 比 A链表 长,那么让 B链表 先走 Lb - La 步;
为什么要用 长的 减去 短的?因为这样得到的结果才是一个 正数 呀,这两个相减得到的值就是 差距步。
其实这道题有点和 链表中倒数第 k 个结点 相似。
既然判断相交要从 头节点 开始走到 尾节点,那么我们就重新定义两个指针 tailA 和 tailB 分别指向 链表A 和 链表B 的头节点,然后开始往后走;
tailA 先走,当 tailA 走到 尾节点 时,就停下来(动图演示)
然后 tailB 再走,当 tailB 走到 尾节点 时,就停下来(动图演示)
注意:这里是走到 尾节点,也就是说当 尾节点 的 next 指向 NULL 时,就停下来。
然后再把 tailA 和 tailB 进行比较,如果它们的 地址 相等,说明相交,就找交点;如果 地址 不相等,就返回 NULL;
既然 地址 相等,那我们就要找交点,但是得先求出 A链表 和 B链表 的长度;
定义两个整型 lenA 和 lenB,分别用来表示长度,初始值设为 1。
计算 lenB 的过程
为什么把 lenA 和 lenB 的 初始值设为 1 呢?
因为要求链表长度,也就是走到 尾节点 就结束了;
也就说从第一个节点开始计算,当走到 尾节点 时,就结束,相当于 尾节点 没有计算,所以就少算了 1 个。
然后就是求出 差距步,让 长 的链表先走 差距步,然后再一起走;
此时 lenB 大于 lenA,求出 差距步 为 1;
所以我们重新定义两个指针,longtList 指向 B 的头节点,shortList 指向 A 的头节点,然后让 longList 先走 差距步,也就是先走 1步(动图演示)
此时再让 longList 和 shortList 一起走,走到相等的位置就停下来(动图演示)
注意:
上面的图中给的链表是 B 长,A 短,但是实际情况有可能是 A 长,B 短;也有可能是 A 和 B 一样长;
所以我们要把长度进行判断,假设默认先设为 A 长,B 短;
如果 lenA 大于 lenB,那么假设成立,就求 差距步;
如果 lenA 小于 lenB,那么说明假设不成立,重新定义即可。
接口代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* tailA, *tailB;
tailA = headA;
tailB = headB;
int lenA = 1; // 存放A链表的长度
int lenB = 1; // 存放B链表的长度
// A链表找尾节点
while (tailA->next) {
tailA = tailA->next;
++lenA;
}
// B链表找尾节点
while (tailB->next) {
tailB = tailB->next;
++lenB;
}
// 如果不相等就返回NULL
if (tailA != tailB) {
return NULL;
}
// 相交,求交点,长的先走"差距步", 然后一起走
struct ListNode* shortList = headA; // 假设A短
struct ListNode* longList = headB; // 假设B长
// 如果A的长度大于B
if (lenA > lenB) {
// 那么就交换一下
longList = headA;
shortList = headB;
}
// 求出差距步
int gap = abs(lenA - lenB); // abs是求绝对值的函数
// 长的先走差距步
while (gap--) {
longList = longList->next;
}
// 然后同时走
while (shortList && longList) {
if (shortList == longList) {
return shortList;
}
shortList = shortList->next;
longList = longList->next;
}
// 要加这个,不然会显示[编译出错]
return NULL;
}