For example, the following two linked lists:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
- If the two linked lists have no intersection at all, return
null
. - The linked lists must retain their original structure after the function returns.
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
该问题求两个单链表(不存在环)相交的第一个节点,若不相交返回null。
算法分析:
step1: 把headA的尾同headB相连接
判断headA是否同headB相交就可转换成判断headA中是否存在环。
通过slow,fast两个指针遍历headA,slow移动一步,fast移动两步。若存在环,则slow,fast会指向一个相同的地址,称之为碰撞点p.
若不存在环,即fast == null or fast.next == null
step2: 若存在环,则从headA的第一个节点和碰撞点,每次移动一步,则他们相交的时候就是两个链表相交的一个节点。
如图所示,若fast,slow在碰撞点为p,假设环的长度为r,整个链表长度为L,LA之间的长度为a,AP之间的长度p。
若slow走了s步,则fast = 2s。
显然存在 2s = s + n*r ---> s = n*r=(n-1)*r+L-a.
而s = a+p,带入式子,可得a = (n-1)*r+L-a-p.注意到L-a-p这段距离就是碰到点到相交点的距离,也就是说,从链表第一个节点,碰撞点同时遍历,他们必定会在第一个相交的点碰撞。
注意:最后还需要断开headA与headB。
public class IntersectionNode {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null)
return null;
ListNode p, q, tmp;
// step1 把headB链接在headA后
p = headA;
while (p.next != null)
p = p.next;
tmp = p;
p.next = headB;
// step2 找到碰撞点
p = headA;
q = headA;
while (q != null && q.next != null) {
p = p.next;
q = q.next.next;
if (p == q) {
break;
}
}
if (q == null || q.next == null) {
tmp.next = null;// 切断headA与headB
return null;
} else {
// step3 找到第一个公共节点
p = headA;
while (p != q) {
p = p.next;
q = q.next;
}
tmp.next = null;// 切断headA与headB
return p;
}
}
//判断链表是否存在环
public boolean isCircle(ListNode headA) {
ListNode slow, fast;
slow = headA;
fast = headA;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
if (fast == null || fast.next == null)
return false;
else {
return true;
}
}
//通过数组创建链表
public ListNode createListNodeFromArray(int[] array) {
ListNode head = new ListNode(array[0]);
ListNode tmp = head;
for (int i = 1; i < array.length; i++) {
ListNode node = new ListNode(array[i]);
tmp.next = node;
tmp = node;
}
return head;
}
//打印
public void print(ListNode headA) {
ListNode p = headA;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
p = null;
}
public static void main(String[] args) {
IntersectionNode intersection = new IntersectionNode();
int[] arrayA = { 1, 3, 5, 7, 9 };
int[] arrayB = { 2, 4, 6, 8, 10 };
int[] arrayC = { 11, 12, 13 };
ListNode headA = intersection.createListNodeFromArray(arrayA);
ListNode headB = intersection.createListNodeFromArray(arrayB);
ListNode headC = intersection.createListNodeFromArray(arrayC);
//headA同headC相连
ListNode p = headA;
while (p.next != null)
p = p.next;
p.next = headC;
intersection.print(headA);
//headB同headC相连
p = headB;
while (p.next != null)
p = p.next;
p.next = headC;
//headA与headB相交
ListNode node = intersection.getIntersectionNode(headA, headB);
System.out.println(node.val);
}
}