【链表】编程判断两个链表是否相交
题目:
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
解答:
方法一:暴力法
对链表A中的每一个结点a,遍历整个链表B,并检查链表B中是否存在结点和a相同。
复杂度分析:
时间复杂度O(mn),空间复杂度O(1)。
方法二:哈希表法
遍历链表A并将每个结点地址/引用存在在哈希表中。然后检查链表B中的每个结点b是否存在于哈希表中。若在,则b为相交结点。
复杂度分析:
时间复杂度O(m+n),空间复杂度O(m)或O(n)。
方法三:双指针法
A. 创建两个指针 pA 和 pB,分别初始化为链表 A
和 B
的头结点。然后让它们向后逐结点遍历。
B. 若pA到达链表的尾部时,将它重定位到链表B的头结点(你没看错,就是链表B);类似的,当pB到达链表的尾部时,将它重定位到链表A的头结点。
C. 若在某一时刻pA和pB相遇,则pA/pB为相交结点。
复杂度分析:
时间复杂度O(m+n),空间复杂度O(1)。
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 12 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) 13 { 14 if (NULL == headA || NULL == headB) 15 { 16 return NULL; 17 } 18 19 ListNode *pA = headA; 20 ListNode *pB = headB; 21 22 while (pA != pB) 23 { 24 pA = (pA == NULL ? headB : pA->next); 25 pB = (pB == NULL ? headA : pB->next); 26 } 27 28 return pA; 29 } 30 };
------------恢复内容开始------------
1、如何判断两个链表(无环)相交?
(1)判断第一个链表中的每个节点是否在第二个链表中,时间复杂度为O(length1*length2);
(2)对第一个链表中的节点地址进行哈希,然后对第二个链表中的地址进行检查;
(3)人为够环,将链表A的尾部节点指向链表B,再判断是否够环成功?从链表B的头节点往下遍历,若能回到B,则说明相交;
(4)判断两个链表的最后一个节点是否相同,如果相交,尾节点肯定为同一个节点;
2、如何判断两个链表(不知是否有环)相交?
先判断是否有环,判断是否有环,可以使用追逐的办法,设置两个指针,一个走一步,一个走两步,如果能相遇,则说明有环。
(1)两个都没有环,则回到问题1;
(2)一个有环,一个无环,不用判断了,肯定链表不相交;
(3)两个都有环:判断链表A中的碰撞点是否出现在链表B中,如果出现,则相交(相交时,环必定共有);
1 #include <iostream> 2 using namespace std; 3 4 5 struct Node 6 { 7 int value; 8 Node * next; 9 }; 10 11 //判断是否有环,返回bool,如果有环,返回环里的节点 12 bool isCircle(Node * head, Node *& circleNode, Node *& lastNode) 13 { 14 Node * fast = head->next; 15 Node * slow = head; 16 while(fast != slow && fast && slow) 17 { 18 if(fast->next != NULL) 19 { 20 fast = fast->next; 21 } 22 23 if(fast->next == NULL) 24 { 25 lastNode = fast; 26 } 27 if(slow->next == NULL) 28 { 29 lastNode = slow; 30 } 31 32 fast = fast->next; 33 slow = slow->next; 34 } 35 //找相交点 36 if(fast == slow && fast && slow) 37 { 38 circleNode = fast; 39 return true; 40 } 41 else 42 { 43 return false; 44 45 } 46 } 47 48 //检测 49 bool detect(Node * head1, Node * head2) 50 { 51 Node * circleNode1; 52 Node * circleNode2; 53 Node * lastNode1; 54 Node * lastNode2; 55 56 bool isCircle1 = isCircle(head1,circleNode1, lastNode1); 57 bool isCircle2 = isCircle(head2,circleNode2, lastNode2); 58 59 //一个有环,一个无环 60 if(isCircle1 != isCircle2) 61 { 62 return false; 63 } 64 //两个都无环,判断最后一个节点是否相等 65 else if(!isCircle1 && !isCircle2) 66 { 67 return lastNode1 == lastNode2; 68 } 69 //两个都有环,判断环里的节点是否能到达另一个链表环里的节点 70 else 71 { 72 Node * temp = circleNode1->next; 73 while(temp != circleNode1) 74 { 75 if(temp == circleNode2) 76 { 77 return true; 78 } 79 temp = temp->next; 80 } 81 return false; 82 } 83 84 return false; 85 } 86 87 int main(int argc, char* argv[]) 88 { 89 Node * n1 = new Node(); 90 Node * n2 = new Node(); 91 Node * n3 = new Node(); 92 Node * n4 = new Node(); 93 94 n1->next = n2; 95 n2->next = n3; 96 n3->next = n4; 97 n4->next = NULL; 98 99 100 Node * n5 = new Node(); 101 Node * n6 = new Node(); 102 Node * n7 = new Node(); 103 Node * n8 = new Node(); 104 105 n5->next = n6; 106 n6->next = n7; 107 n7->next = n8; 108 n8->next = n5; 109 110 if(detect(n1,n2)) 111 { 112 printf("相交\n"); 113 } 114 else 115 { 116 printf("不相交\n"); 117 } 118 119 return 0; 120 }
------------恢复内容结束------------