一、判断一个链表是否成环
解法1:哈希表
使用哈希表,在遍历结点的过程中把结点放到哈希表中,每一次都去查结点有没有在哈希表,
如果查到某个结点在哈希表中(这里find如果没找到,会返回end,此时继续放结点到哈希表),如果查到了,就返回那个结点。
这里可以将flag改成结点的形式,找到了返回那个结点,找不到就返回NULL
时间复杂度:O(n), 对于含 n 个元素的链表,我们访问每个元素最多一次。添加一个结点到哈希表中只需要花费 O(1) 的时间。
空间复杂度:O(n), 空间取决于添加到哈希表中的元素数目,最多可以添加 n 个元素。
解法2:快慢指针
就像跑四百米,跑得快的人一定能追上跑的慢的人。
时间复杂度:
- 若不存在环,则时间取决于链表的长度,也就是O(N)
- 如果存在环,则时间复杂度为O(N+K),N为非环部分长度,K为环形部分长度
空间复杂度:O(1)
二、判断两个无环链表是否相交并返回第一个相交结点
如果通过一
中得到的两个loop环入口结点均为空(NULL),那么这两个链表无环,两个无环链表即可能相交,也可能不相交
2.1 解法1 - 哈希表
思路
- 首先遍历链表A,把链表A中所有结点放到哈希set中
- 然后遍历链表B,去查这个哈希表,看哈希表中是否有B的结点,如果有,就相交,没有则不相交
2.2 解法2 - 不使用哈希表
思路
两个无环链表若相交,它们的尾结点的地址一定是相同的,于是分别统计两个链表的长度,获得两个链表的最后一个结点
2.3 无环链表相交情况测试
三、判断两个有环链表是否相交并返回第一个相交结点
如果通过一
中得到的两个loop环入口结点均不为空(NULL),那么这两个链表有环,两个有环链表既可能相交,也可能不相交
那么,会有下面的这三种情况
- 两有环链表先相交,后共享环
(loop1 == loop2)
- 两有环链表各自成环,不相交
(loop1 != loop2)
- 两有环链表“野马”成环
(loop1 != loop2)
3.1 两有环链表先相交,后共享环
这种情况下,两个链表的环入口结点是相同的地址,于是,这种情况跟两个无环链表相交问题是类似的
只不过我们需要把原来的NULL作为最后改为loop作为最后(否则不就死循环了嘛)
两有环链表先相交,后共享环测试
3.2 两有环链表各自成环不相交及野马成环
这种情况下,获取的两个链表的环入口结点loopA和loopB是不相等的
于是可以从loopA的下一个结点开始,一直往下走
- 如果一直到转回自己还没有遇到loopB,就说明不相交,返回NULL
- 如果在转回自己的过程中遇到了loopB,就说明相交,此时可以返回loopA(离链表A的头近),也可以返回looB(离链表B的头近)
两有环链表各自成环,不相交测试
两有环链表“野马”成环测试
测试代码
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <climits>
#include <iomanip>
#include <stack>
#include <set>
#include <unordered_set>
using namespace std;
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* GetIntersectListNode(ListNode *headA, ListNode *headB) {
if (headA == NULL || headB == NULL)
return NULL;
ListNode* loopListNodeA = GetLoopListNode(headA);
if (loopListNodeA == NULL)
cout << " - 链表A无环\n";
else
cout << " - 链表A的环入口结点 = " << loopListNodeA->val << endl;
ListNode* loopListNodeB = GetLoopListNode(headB);
if (loopListNodeB == NULL)
cout << " - 链表B无环\n";
else
cout << " - 链表B的环入口结点 = " << loopListNodeB->val << endl;
if (loopListNodeA == NULL && loopListNodeB == NULL) {
cout << " - 两条链表均无环,现在找第一个相交结点...\n";
return noLoopMode2(headA, headB);
}
else if (loopListNodeA != NULL && loopListNodeB != NULL) {
cout << " - 两条链表均有环,现在找第一个相交结点...\n";
return bothLoopMode(headA, loopListNodeA, headB, loopListNodeB);
}
else {
cout << " - 一个链表有环,另一个链表无环,一定不相交(单链表)\n";
return NULL;
}
}
// 两个链表无环时,可以使用哈希表
ListNode* noLoopMode1(ListNode *headA, ListNode *headB) {
ListNode *cur = headA;
unordered_set<ListNode*> SetNodes;
unordered_set<ListNode*>::iterator iter;
while (cur != NULL) {
if ((iter = SetNodes.find(cur)) == SetNodes.end()) {
SetNodes.insert(cur);
cur = cur->next;
} else {
break;
}
}
cur = headB;
while (cur != NULL) {
if ((iter = SetNodes.find(cur)) == SetNodes.end()) {
cur = cur->next;
} else {
return cur;
}
}
return NULL; // 一直到headB到头了还没查到,就不相交
}
// 两个链表无环时,也可以不使用哈希表
// 方法是分别统计两个链表的长度,分别获得两个链表的最后一个结点
ListNode* noLoopMode2(ListNode *headA, ListNode *headB) {
ListNode *curA = headA;
ListNode *curB = headB;
int n = 0; // 两链表长度的差值
while (curA->next != NULL) { // curA的next为空,说明curA是最后一个结点
n++;
curA = curA->next;
}
while (curB->next != NULL) {
n--;
curB = curB->next;
}
if (curA != curB) // 此时curA和curB是最后一个结点,不等就不可能相交
return NULL;
// 此时curA和curB虽然相等了,但并不是第一个相交的结点
// 于是让curA指向长的链表,curB指向短的链表
curA = ((n > 0) ? headA : headB);
if (curA == headA)
curB = headB;
else
curB = headA;
n = fabs(n);
while (n > 0) {
curA = curA->next;
n--;
}
while (curA != curB) {
curA = curA->next;
curB = curB->next;
}
return curA;
}
ListNode* bothLoopMode(ListNode *headA, ListNode *loopA, ListNode *headB, ListNode *loopB) {
if (loopA == loopB) {
ListNode *curA = headA;
ListNode *curB = headB;
int n = 0;
while (curA->next != loopA) { // 注意这里是loopA而不再是NULL,因为有环
n++;
curA = curA->next;
}
while (curB->next != loopB) { // 同理
n--;
curB = curB->next;
}
curA = ((n > 0) ? headA : headB);
if (curA == headA)
curB = headB;
else
curB = headA;
while (n > 0) {
n--;
curA = curA->next;
}
while (curA != curB) {
curA = curA->next;
curB = curB->next;
}
return curA;
} else {
ListNode *cur = loopA->next;
while (cur != loopA) {
if (cur == loopB)
return loopA;
cur = cur->next;
}
return NULL;
}
}
ListNode* GetLoopListNode(ListNode *head) {
if (head == NULL || head->next == NULL || head->next->next == NULL)
return NULL;
ListNode *quick = head->next->next;
ListNode *slow = head->next;
while (quick != slow) {
if (quick->next == NULL || quick->next->next == NULL)
return NULL;
quick = quick->next->next;
slow = slow->next;
}
quick = head;
while (quick != slow) {
quick = quick->next;
slow = slow->next;
}
return quick;
}
void print(ListNode *head) {
ListNode *cur = head;
ListNode *loop = GetLoopListNode(head);
if (loop == NULL) {
while (cur != NULL) {
cout << cur->val << "-->";
cur = cur->next;
}
cout << "null" << endl;
return;
} else {
int n = 0;
while (n < 3) {
if (cur == loop) {
n++;
}
cout << cur->val << "-->";
cur = cur->next;
}
cout << "...";
}
cout << endl;
}
};
int main(int argc, char *argv[]) {
Solution s;
cout << "===================== Part 1 : 两条无环链表 =====================\n\n";
cout << "1. ==== 两个无环链表相交测试 ====\n";
ListNode *head1 = new ListNode(1);
head1->next = new ListNode(2);
head1->next->next = new ListNode(3);
head1->next->next->next = new ListNode(4);
head1->next->next->next->next = new ListNode(5);
head1->next->next->next->next->next = new ListNode(6);
head1->next->next->next->next->next->next = new ListNode(7);
cout << " - 无环链表head1初始化完毕:";
s.print(head1);
ListNode *head2 = new ListNode(0);
head2->next = new ListNode(9);
head2->next->next = new ListNode(8);
head2->next->next->next = head1->next->next->next->next->next;
cout << " - 无环链表head2初始化完毕:";
s.print(head2);
cout << " - 两个无环链表的第一个相交结点为:" << s.GetIntersectListNode(head1, head2)->val << endl;
cout << "1. ============ end =============\n\n";
cout << "2. ==== 两无环链表不相交测试 ====\n";
ListNode *head3 = new ListNode(1);
head3->next = new ListNode(2);
head3->next->next = new ListNode(3);
cout << " - 无环链表head3初始化完毕:";
s.print(head3);
ListNode *head4 = new ListNode(0);
head4->next = new ListNode(2);
head4->next->next = new ListNode(1);
cout << " - 无环链表head4初始化完毕:";
s.print(head4);
if (s.GetIntersectListNode(head3, head4) == NULL)
cout << " - 两条无环链表不相交\n";
cout << "2. ============ end =============\n\n";
cout << "\n===================== Part 2 : 两条有环链表 =====================\n\n";
cout << "1. ==== 两有环链表不相交测试 ====\n";
ListNode *head5 = new ListNode(1);
head5->next = new ListNode(2);
head5->next->next = new ListNode(3);
head5->next->next->next = new ListNode(4);
head5->next->next->next->next = new ListNode(5);
head5->next->next->next->next->next = head5->next;
cout << " - 有环链表head5初始化完毕:";
s.print(head5);
ListNode *head6 = new ListNode(1);
head6->next = new ListNode(2);
head6->next->next = new ListNode(3);
head6->next->next->next = new ListNode(4);
head6->next->next->next->next = new ListNode(5);
head6->next->next->next->next->next = head6->next->next->next;
cout << " - 有环链表head6初始化完毕:";
s.print(head6);
if (s.GetIntersectListNode(head5, head6) == NULL)
cout << " - 两条有环链表不相交\n";
cout << "1. ============ end =============\n\n";
cout << "2. ==== 两有环链表相交测试 ====\n";
ListNode *head7 = new ListNode(1);
head7->next = new ListNode(2);
head7->next->next = new ListNode(3);
head7->next->next->next = new ListNode(4);
head7->next->next->next->next = new ListNode(5);
head7->next->next->next->next->next = new ListNode(6);
head7->next->next->next->next->next->next = new ListNode(7);
head7->next->next->next->next->next->next->next = head7->next->next->next->next;
cout << " - 有环链表head7初始化完毕:";
s.print(head7);
ListNode *head8 = new ListNode(1);
head8->next = new ListNode(2);
head8->next->next = head7->next->next->next;
cout << " - 有环链表head7初始化完毕:";
s.print(head8);
cout << " - 两个有环链表的第一个相交结点为:" << s.GetIntersectListNode(head7, head8)->val << endl;
cout << "2. ============ end =============\n\n";
cout << "3. ==== 两有环链表相交测试 ====\n";
ListNode *head9 = new ListNode(1);
head9->next = new ListNode(2);
head9->next->next = new ListNode(3);
head9->next->next->next = new ListNode(4);
head9->next->next->next->next = head9->next;
cout << " - 有环链表head9初始化完毕:";
s.print(head9);
ListNode *head10 = new ListNode(1);
head10->next = head9->next->next->next;
cout << " - 有环链表head10初始化完毕:";
s.print(head10);
cout << " - 两个有环链表的第一个相交结点为:" << s.GetIntersectListNode(head9, head10)->val << endl;
cout << "3. ============ end =============\n\n";
return 0;
}