【链表】编程判断两个链表是否相交

题目:

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:

 

 

 

 

在节点 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 }

 

 

------------恢复内容结束------------

posted @ 2020-05-01 16:56  梦醒潇湘  阅读(346)  评论(0)    收藏  举报