LeetCode上的一道题,编写一个程序,找到两个单链表相交的起始节点。
初始解法
题目连接:两个链表相交的第一个结点
首先,我们先来看起初的解法:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode curA = headA, curB = headB;
while (curA != curB) {
curA = curA == null ? headB : curA.next;
curB = curB == null ? headA : curB.next;
}
return curA;
}
}
解题思路:
虽然上面的答案能够通过,但是这个答案是有问题的,因为我们没有考虑链表有环的情况,如果链表中有环的话,上面的解答就是错的。
考虑链表有环的情况
考虑链表有环,我们可以分情况进行讨论,如下:
一共有六种情况,如上图。
解题思路:
- 首先判断两个链表是否带环,如果都不带环,按照前面判断相交的方法判断,情况1和情况2;
- 如果一个链表带环,一个链表不带环,则两个链表不可能相交,情况4;
- 如果两个链表都带环,分别求两个环的入口点,如果入口点一样,则为情况5,如果入口点不一样,则从一个入口点出发,绕环一周,看能不能遇到另一个入口点,如果能够遇到,就是情况6,否则就是情况3。
代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
boolean flagA = hasCircle(headA);
boolean flagB = hasCircle(headB);
// 两个链表都没有环
if (flagA == false && flagB == false) {
ListNode curA = headA, curB = headB;
while (curA != curB) {
curA = curA == null ? headB : curA.next;
curB = curB == null ? headA : curB.next;
}
return curA;
}
// 一个链表有环,一个链表没有环
else if (flagA == false || flagB == false) {
return null;
}
// 两个链表都有环
else {
ListNode entranseA = findEntranseNode(headA);
ListNode entranseB = findEntranseNode(headB);
// 环入口结点一致
if (entranseA == entranseB) {
return entranseA;
}
// 环入口结点不一致
else {
HashSet<ListNode> set = new HashSet<>();
ListNode cur = entranseA.next;
while (cur != entranseA) {
// 从一个入口点出发,遇到了另一个入口点,环上相交
if (set.contains(entranseB)) {
ListNode curA = entranseA, curB = entranseB;
while (curA != curB) {
curA = curA.next;
curB = curB.next;
}
return curA;
}
set.add(cur);
cur = cur.next;
}
// 从一个入口点出发,没有遇到另一个入口点,不相交
return null;
}
}
}
// 寻找环的入口结点
private ListNode findEntranseNode(ListNode head) {
ListNode fast = head, slow = head;
while (true) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
fast = head;
while (fast != slow) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
// 判断一个链表是否有环
private boolean hasCircle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode fast = head, slow = head;
while (true) {
if (fast == null || fast.next == null) {
return false;
}
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
return true;
}
}