题目描述:

判断两个单链表是否相交?假设链表没有环。

假如链表有环呢?

1.  假如没有环

那么如果两个链表相交的话,必然最后的节点一定是同一个节点。所以只需要各自扫描一遍链表,找到最后一个节点,比较是否相同即可。

O ( M + N)

// version 1
// test whether two lists are intersected
// assume each list has no circle
bool IsIntersectedNoCircle(ListNode *lhs, ListNode *rhs)
{
if(lhs == NULL || rhs == NULL)
return false; ListNode *tail1(lhs);
for(; tail1->next; tail1 = tail1->next); ListNode *tail2(lhs);
for(; tail2->next; tail2 = tail2->next); return tail1 == tail2;
}

2. 可能有环

首先,如何判断是否有环?

采用快慢指针,一个指针一次走两步,一个指针一次走一步,如果链表有环的话,必然最后慢指针会赶上快指针。

复杂度同样是 O ( M + N)。

如果还要求求出 进入环的那个节点: 可以用两个指针,一个从链表head 出发,另一个从刚刚快慢指针的相遇点出发,速度相同。

可以证明,两指针必定在入口处第一次相遇。

// test whether list has a circle
// if true, return the enter node
// if not, return NULL
ListNode* HasCircle(ListNode *list)
{
if(list == NULL || list->next == NULL)
return NULL; // fast/slow pointer method
// if circled, slow pointer will catch up with fast one
ListNode *fast(list), *slow(list); while(fast)
{
fast = fast->next;
if(fast == NULL) return NULL;
fast = fast->next;
slow = slow->next; if(fast == slow)
break;
}
assert(fast == NULL || slow == fast); if(fast == NULL)
return NULL; // list definitely has a circle
// find the enter node
// fast and enter will meet at the enter node
ListNode *enter(list); while(enter != fast)
{
enter = enter->next;
fast = fast->next;
} return enter;
}

根据是否有环,可以分为以下三个 case:

case 1: 都没有环:已经分析

case 2: 都有环: 注意到如果相交,这两个环必定是一模一样的。所以,只要判断是否有一个节点在另一个环中即可。

case 3: 一个有环,一个没有环: 一定不相交

// version 2
// assume lists may have a circle inside
bool IsIntersectedCircle(ListNode *lhs, ListNode *rhs)
{
ListNode *enter1(NULL), *enter2(NULL); enter1 = HasCircle(lhs);
enter2 = HasCircle(rhs); // case 1: both lists have no circles
if(enter1 == NULL && enter2 == NULL)
{
return IsIntersectedNoCircle(lhs, rhs);
}
// case 2: each have a circle
else if(enter1 && enter2)
{
ListNode *node(enter1->next); while(node != enter1 && node != enter2){
node = node->next;
}
return node == enter2;
}
// case 3: one has a circle, while the other not
else
{
return false;
}
}

完整代码如下:

// copyright @ L.J.SHOU Feb.27, 2014
// test whether two lists are intersected
#include <iostream>
#include <cassert>
using namespace std; struct ListNode{
int val;
ListNode *next;
ListNode(int x)
:val(x), next(NULL){}
}; ListNode* HasCircle(ListNode*);
bool IsIntersectedCircle(ListNode*, ListNode*); // version 1
// test whether two lists are intersected
// assume each list has no circle
bool IsIntersectedNoCircle(ListNode *lhs, ListNode *rhs)
{
if(lhs == NULL || rhs == NULL)
return false; ListNode *tail1(lhs);
for(; tail1->next; tail1 = tail1->next); ListNode *tail2(lhs);
for(; tail2->next; tail2 = tail2->next); return tail1 == tail2;
} // version 2
// assume lists may have a circle inside
bool IsIntersectedCircle(ListNode *lhs, ListNode *rhs)
{
ListNode *enter1(NULL), *enter2(NULL); enter1 = HasCircle(lhs);
enter2 = HasCircle(rhs); // case 1: both lists have no circles
if(enter1 == NULL && enter2 == NULL)
{
return IsIntersectedNoCircle(lhs, rhs);
}
// case 2: each have a circle
else if(enter1 && enter2)
{
ListNode *node(enter1->next); while(node != enter1 && node != enter2){
node = node->next;
}
return node == enter2;
}
// case 3: one has a circle, while the other not
else
{
return false;
}
} // test whether list has a circle
// if true, return the enter node
// if not, return NULL
ListNode* HasCircle(ListNode *list)
{
if(list == NULL || list->next == NULL)
return NULL; // fast/slow pointer method
// if circled, slow pointer will catch up with fast one
ListNode *fast(list), *slow(list); while(fast)
{
fast = fast->next;
if(fast == NULL) return NULL;
fast = fast->next;
slow = slow->next; if(fast == slow)
break;
}
assert(fast == NULL || slow == fast); if(fast == NULL)
return NULL; // list definitely has a circle
// find the enter node
// fast and enter will meet at the enter node
ListNode *enter(list); while(enter != fast)
{
enter = enter->next;
fast = fast->next;
} return enter;
} // destroy list
ListNode* Destroy(ListNode *list)
{
ListNode *next(NULL); while(list)
{
next = list->next;
delete list;
list = next;
} return NULL;
} int main(void)
{
ListNode *list(NULL); // testing case 1: both have no circles
list = new ListNode(1);
list->next = new ListNode(2);
list->next->next = new ListNode(3); ListNode *list2 = list->next;
cout << IsIntersectedCircle(list, list2) << endl; // testing case 2: both have circles
list2 = new ListNode(1);
list2->next = new ListNode(2);
list2->next->next = list->next; list->next->next->next = list->next;
cout << IsIntersectedCircle(list, list2) << endl; list->next->next->next = NULL;
list2->next->next = NULL; // testing case 3: only one has a circle
list->next->next->next = list->next;
cout << IsIntersectedCircle(list, list2) << endl;
list->next->next->next = NULL; list = Destroy(list);
list2 = Destroy(list2); return 0;
}

Interview----判断两个链表是否相交?的更多相关文章

  1. Oracle判断两个时间段是否相交

    SQL中常常要判断两个时间段是否相交,该如何判断呢?比如两个时间段(S1,E1)和(S2,E2).我最先想到的是下面的方法一.方法一:(S1 BETWEEN S2 AND E2) OR (S2 BET ...

  2. IT公司100题-7-判断两个链表是否相交

    问题:有一个单链表,其中可能有一个环,也就是某个节点的next指向的是链表中在它之前的节点,这样在链表的尾部形成一环.1.如何判断一个链表是不是这类链表? 问题扩展:1.如果链表可能有环呢?2.如果需 ...

  3. C# 判断两条直线是否相交

    直接上代码,过程不复杂 /// <summary> /// 判断两条线是否相交 /// </summary> /// <param name="a"& ...

  4. PHP判断两个矩形是否相交

    <?php $s = is_rect_intersect(1,2,1,2,4,5,0,3); var_dump($s); /* 如果两个矩形相交,那么矩形A B的中心点和矩形的边长是有一定关系的 ...

  5. C# 判断两个矩形是否相交

    源代码 public bool JudgeRectangleIntersect(double RecAleftX, double RecAleftY, double RecArightX, doubl ...

  6. cocos2d-x 判断两条直线是否相交

    bool GraphicsUtil::linesCross(b2Vec2 v0, b2Vec2 v1, b2Vec2 t0, b2Vec2 t1, b2Vec2 &intersectionPo ...

  7. Cracking the Coding Interview:: 寻找有环链表的环路起始节点

    给定一个有环链表,实现一个算法返回环路的开头节点. 这个问题是由经典面试题-检测链表是否存在环路演变而来.这个问题也是编程之美的判断两个链表是否相交的扩展问题. 首先回顾一下编程之美的问题. 由于如果 ...

  8. 如何判断单链表是否存在环 & 判断两链表是否相交

    给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针sl ...

  9. You can Solve a Geometry Problem too (hdu1086)几何,判断两线段相交

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/3276 ...

随机推荐

  1. Python--关于 join 和 split

    .join() join将 容器对象 拆分并以指定的字符将列表内的元素(element)连接起来,返回字符串(注:容器对象内的元素须为字符类型) >>> a = ['no','pai ...

  2. Linux基础: 挂载镜像文件(Mount & ISO)

    ISO/Ghost 镜像文件概念(裸机安装,无光驱安装,跨平台安装) ISO是镜像文件:所谓镜像文件其实和ZIP压缩包类似,它将特定的一系列文件按照一定的格式制作成单一的文件,以方便用户下载和使用,例 ...

  3. ASP.NET Web API中的依赖注入

    什么是依赖注入 依赖,就是一个对象需要的另一个对象,比如说,这是我们通常定义的一个用来处理数据访问的存储,让我们用一个例子来解释,首先,定义一个领域模型如下: namespace Pattern.DI ...

  4. js——<script>标签的加载顺序

    用了很久的JavaScript,今天突然就碰见了将一个js文件放在<head></head>与<body></body>标签中,一个不可以执行,一个可以 ...

  5. Dapper使用

    公司的项目使用了Dapper做数据库连接处理,感觉不错,自己研究一下怎么用. 在网上找了找资料对Dapper都比较推崇.主要是两个方面,一个是连接速度很快,一个是代码开源且简单,只有一个SqlMapp ...

  6. [Hadoop入门] - 1 Ubuntu系统 Hadoop介绍 MapReduce编程思想

    Ubuntu系统 (我用到版本号是140.4) ubuntu系统是一个以桌面应用为主的Linux操作系统,Ubuntu基于Debian发行版和GNOME桌面环境.Ubuntu的目标在于为一般用户提供一 ...

  7. weblogic热部署问题

    最近部署的项目在weblogic10上面.按说10已经支持热部署了,但是为什么我每次修改的jsp,不生效,必须重启服务器呢?这样太耽误时间了,后来发现我的weblogic.xml里的servlet-r ...

  8. 二模 (10)day1

    第一题: 题目描述: 一个阅览室每天都要接待大批读者.阅览室开门时间是0,关门时间是T.每位读者的到达时间都不一样,并且想要阅读的刊物不超过5本.每位读者心里对自己想看的刊物都有一个排位,到达之后他会 ...

  9. wScratchPad 实现刮刮卡效果

    插件网址http://wscratchpad.websanova.com/

  10. JavaScript数字精度上代码。

    /**不能超过 9007199254740992 * floatObj 包含加减乘除四个方法,能确保浮点数运算不丢失精度 * * 我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差), ...