链表操作 -- 两个链表间的相交性问题

一世执手 提交于 2020-03-23 14:49:15

 

本文参考:

  http://blog.csdn.net/g_brightboy/article/details/6824834

  http://blog.csdn.net/huangxy10/article/details/8014233

  在此致谢。

 

 

  • 问题:

  给定两个链表,判断它们是否相交。

 

注意:

  如果两个链表相交的话,则公用相交点开始往后的所有节点。【因为节点的next指针只有一个!】

 

解答:

  1)首先来看最直观的方法,也就是一次判断链表A中的节点是否在链表B中出现。

  时间复杂度:O(n2)

  空间复杂度:O(1)

  

1 bool List::isIntersect(Node* listA,Node* listB){
2     for(Node* headA = listA; headA != NULL ; headA =  headA->next){
3         for(Node* headB = listB; headB != NULL; headB = headB->next){
4             if(headA == headB)
5                 return true;
6         }
7     }   
8     return false;                                                                                                      
9 }
View Code

  

  2)在方法(1)中,链表A中节点每次都需要匹配链表B中每个节点,这个匹配动作的时间复杂度为O(n)。考虑使用Hash来存储链表B,这样可将匹配动作的时间复杂度降低为O(1)。

  时间复杂度:O(n)

  空间复杂度:O(n)

 

 1 bool isIntersect(Node* listA,Node* listB){
 2     unordered_map<Node*,bool> hashTable;
 3 
 4     for(Node* tmp = listA; tmp != NULL; tmp=tmp->next)
 5     {
 6         hashTable.insert(pair<Node*,bool>(tmp,true));
 7     }
 8 
 9     for(Node* tmp = listB; tmp != NULL; tmp=tmp->next)
10     {
11         unordered_map<Node*,bool>::iterator iter = hashTable.find(tmp);
12         if(iter!=hashTable.end() && iter->second)
13             return true;
14     }
15 
16     return false;
17 }
View Code

  

  3)考虑当两个链表相交时,自相交点之后的所有节点都一样。因此,当两个链表的尾节点一样时就是相交的。

  时间复杂度:O(n)

  空间复杂度:O(1)

 

 1 bool isIntersect(Node* listA,Node* listB)
 2 {
 3     if(listA==NULL || listB==NULL)
 4         return false;
 5 
 6     Node* tailA = listA;
 7     while(tailA->next != NULL)
 8         tailA = tailA->next;
 9     
10     Node* tailB = listB;
11     while(tailB->next != NULL)
12         tailB = tailB->next;
13 
14     return (tailA == tailB);
15 }
View Code

 
  4)思考之前处理的 “判断链表是否有环”的问题。 当链表A与链表B相交时,将链表A的首尾相连,则链表B中出现环。

  时间复杂度:O(n)

  空间复杂:O(1)

  

 1 bool hasCycle(Node* listB)
 2 {
 3     if(listB==NULL)
 4         return false;
 5 
 6     Node* fast = listB->next;
 7     Node* slow = listB;
 8 
 9     while(fast!=NULL && fast->next!=NULL)
10     {
11         fast = fast->next->next;
12         slow = slow->next;
13 
14         if(fast == slow)
15             return true;
16     }
17     return false;
18 }
19 
20 bool isIntersect(Node* listA,Node* listB)
21 {
22     if(listA == NULL || listB == NULL)
23         return false;
24 
25     Node* tailA = listA;
26     while(tailA->next != NULL)
27         tailA = tailA->next;
28 
29     tailA->next = listA;
30 
31     return hasCycle(listB);     
32 
33 }
View Code

 

  5)More ?

 

  • 问题

  求两个相交链表的第一个交点

  

  解答:

  1)将链表A收尾相连,之后“寻找有环链表的首个环节点”

  

 

 1 Node* find_cycle_begin(Node* list)
 2 {
 3     Node* fast = list->next;
 4     Node* slow = list;
 5 
 6     while(fast != NULL && fast->next !=NULL)
 7     {
 8         fast = fast->next->next;
 9         slow = slow->next;
10 
11         if(fast == slow)
12             break;
13     }
14 
15     fast = fast->next;
16     slow = list;
17 
18     while(fast != slow)
19     {
20         fast = fast->next;
21         slow = slow->next;
22     }
23 
24     return fast;
25 }
26 
27 Node*  isIntersect(Node* listA,Node* listB)
28 {
29     if(listA == NULL)
30         return (new Node(-1));
31 
32     Node* tail = listA; 
33     while(tail->next != NULL)
34         tail = tail->next;
35 
36     tail->next = listA;
37 
38     return find_cycle_begin(listB);    
39 }
View Code

 

  

  2)依次比较

    可用加速操作:

        [1].假设链表A的长度lenA大于链表B的lenBa。在第一个交点的位置一定在链表的后lenB的内。可以不用判断前lenA - lenB个节点。

        [2].将链表A的节点存储在hash表中,一次检查链表B中的节点。

        [3].使用两个指针来分别遍历两个队列,当指针到达尾部时,将指针切换到另一个队列的头部,在两个指针都切换后,如果两个队列存在相交,则

    在指针在此到达尾部前会相遇。

        原因:这种控制,可以使得两个指针移动相同的距离。 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!