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

本文参考:

  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 }

  

  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 }

  

  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 }

  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 }

  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 }

  

  2)依次比较

    可用加速操作:

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

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

时间: 2024-10-16 07:47:19

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

链表操作 -- 有环链表问题

参考: http://blog.163.com/[email protected]/blog/static/1113522592011828104617420/ 问题: 判断一个链表中是否有环. 分析: 我们都知道,当一个链表中没有环时,我们使用一个指针能从头遍历到尾:当链表中有环时,链表会在环中旋转. 当我们只使用一个链表指针时,可想到方法就是使用额外的数据结构来存储遍历过的每个节点,在遍历next节点时,判断next节点是否已存在于存储的节点中. 存储结构可以选择为hashTable,这样的

【链表】两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点. 1 public class Solution { 2 3 /** 4 * 思路:两个链表相交,存在公共的链表尾,根据链表长度的差值,移动指针,找到第一个相同的节点,即为第一个公共节点 5 * @param pHead1 6 * @param pHead2 7 * @return 8 */ 9 public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 10 11 if

链表操作 -- 未排序链表的处理问题

问题: 删除未排序链表中的重复元素. 解答: 1)最朴素的方法就是将链表排序,然后遍历并删除其中的重复元素.这种方法的时间复杂度依赖于排序的过程. 在此,我们要思考一下,找到并且删除链表中的重复元素真的需要排序过程吗? 2)如何才能在不排序的情况下找到重复元素? 最朴素的方法就是处理每个节点的时候,遍历剩余的节点,查看其中是否有重复的元素.这种方法的时间复杂度较高,O(n2). 有没有更好的算法或是数据结构来帮助我们降低这个时间复杂度?这种查找某个元素的存在性问题,可以借助于hash表来快速的实

复习下C 链表操作(单向链表)

Object-C 作为C 的包装语言(运行时.消息机制).如果不熟悉C 的话实在玩得太肤浅. 随便深入oc 内部都会接触到C. runtime .GCD.Block.消息机制... 所有强大的功能无不用的 包装体(struct 结构体).使用GCC/Clang (可以google 下.Clang 比GCC 更优化,) 编译指令. 转换OC 为 C . 终端 使用Clang 命令参考 clang -rewrite-objc file.m 查看file.cpp 文件为编译转换的C 单向链表 创建 .

JAVA 链表操作:循环链表

主要分析示例: 一.单链表循环链表 二.双链表循环链表 其中单链表节点和双链表节点类和接口ICommOperate<T>与上篇一致,这里不在赘述.参考:JAVA链表操作:单链表和双链表http://www.cnblogs.com/xiaoxing/p/5969133.html 一.单链表循环链表 package LinkListTest; import java.util.HashMap; import java.util.Map; public class SingleCycleLinkLi

[链表]同时遍历两个链表

两个有序链表的合并 对于两个有序链表合并成一个新的有序链表的代码很简单,但是要注意一些测试用例: 比如说一个为空链表:两个链表不一样长,肯定最后有一个链表要单独的挂到结果链表中去的. ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(l1 == NULL) return l2; if(l2 == NULL) return l1; ListNode dummy(-1); ListNode *p = &dummy; while(l1 !

10、单链表操作

单链表操作 单链表操作1 /*单链表的类型定义*/ typedef int DataType; typedef struct node { DataType data; struct node * next; }LinkNode, *LinkList; /*单链表的定位运算*/ LinkNode *Locate(LinkNode *L, int k)//????为什么此处是LinkNode *Locate()类型,表示什么意思 { LinkNode *p; int i; i= 1; p = L-

编程之美3.6—判断两个链表是否相交

解法一: 判断第一个链表的每个节点是否在第二个链表中,O(M*N): 解法二: 对第一个链表的节点地址hash排序,建立hash表,然后对第二个链表的每个节点的地址查询hash表,如出现,相交 时间复杂度O(M+N),空间复杂度O(M). 解法三: 把第二个链表接在第一个链表后面,得到的链表有环,相交,否则,不相交.' 第二个链表的表头一定在环上,只需从第二个链表开始遍历 时间复杂度O(N),常数空间 解法四: 如果两个没有环的链表相交于某一节点,那么在这个节点之后的所有节点都是两个链表共有的.

判断两个链表是否相交(带环)

解决方案: 1.找出链表1的环入口节点a1,链表2的环入口节点a2; 2.如果a1=a2; 说明两个链表可能在入环之前或者入环第一个节点相交:将a1,a2作为两个链表的最后一个节点,转化为不带环的链表相交:其实在这种情况下已经说明两个链表已经相交了. 3.如果a1!=a2;以a1为基准节点进行while循环,如果在循环中找到跟a2相同的节点,说明两个链表相交:如果没找到,说明不相交. #如果1个链表不带环,1个链表带环:则两个链表必不相交: