Write a program to find the node at which the intersection of two singly linked lists begins.
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.
- If the two linked lists have no intersection at all, return
分析:此题很有意思,联想到以前做过的linkedlist cycle II,我们不难想出reverse B然后将A和B连在一起,如果A和B有交点,那么A和B连在一起后一定有环,此时我们便可以用linked list cycle II的解法。代码如下:
1 class Solution { 2 public: 3 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 if(headA == NULL || headB == NULL) return NULL; 5 if(headA == headB) return headA; 6 7 ListNode *end = reverse(headB);//reverse B 8 headB->next = headA;//construct a circle 9 10 ListNode *result = detectCycle(end); 11 headB->next = NULL; 12 headB = reverse(end); 13 14 return result; 15 } 16 ListNode *reverse(ListNode *head){ 17 if(head == NULL || head->next == NULL) return head; 18 ListNode dummy(-1); 19 dummy.next = head; 20 for(ListNode *pre = head, *p = head->next; p; p = pre->next){ 21 pre->next = p->next; 22 p->next = dummy.next; 23 dummy.next = p; 24 } 25 return dummy.next; 26 } 27 28 ListNode *detectCycle(ListNode *head) { 29 if(head == NULL || head->next == NULL) return NULL; 30 31 ListNode *slow = head, *fast = head; 32 //find meeting point 33 while(slow->next && fast && fast->next){ 34 slow = slow->next; 35 fast = fast->next->next; 36 if(slow == fast) break; 37 } 38 //no cycle 39 if(slow != fast) return NULL; 40 //find cycle beginning 41 fast = head; 42 while(fast != slow){ 43 fast = fast->next; 44 slow = slow->next; 45 } 46 return fast; 47 } 48 };
此题还有另一种解法,这种题利用的都是几何距离关系,我们只要两个linked list到相交点距离的差值d,便可以很快找出相交点。当我们遍历完长度短的linked list时,长度长的linked list只访问到记录末尾距离为d。我们可以通过这点设计算法。假设两个linked list A和B, A的长度小于B的长度,我们分别用pA和pB遍历两个链表,当pA到达末尾时,将pA更新为链表B的头,然后接着遍历,知道pB达到末尾,此时将pB更新为链表A的头,继续遍历直到pA=pB。代码如下:
1 class Solution { 2 public: 3 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { 4 if(headA == NULL || headB == NULL) return NULL; 5 if(headA == headB) return headA; 6 7 ListNode *pA = headA, *pB = headB; 8 while(pA && pB){ 9 pA = pA->next; 10 pB = pB->next; 11 } 12 if(pA == NULL && pB == NULL){ 13 pA = headA; 14 pB = headB; 15 }else if(pA == NULL){ 16 pA = headB; 17 while(pB){ 18 pB = pB->next; 19 pA = pA->next; 20 } 21 pB = headA; 22 }else{ 23 pB = headA; 24 while(pA){ 25 pA = pA->next; 26 pB = pB->next; 27 } 28 pA = headB; 29 } 30 while(pA && pB){ 31 if(pA == pB) return pA; 32 pA = pA->next; 33 pB = pB->next; 34 } 35 return NULL; 36 } 37 };