今天才发现,当年考研的最后一题还有常数上更优的时间复杂度算法。。。
判断两个单链表是否相交:
我写的:
遍历Link1,O(L1)
遍历Link2,O(L2)
将长的链表指针后移|L2-L1|个长度,然后两个指针逐个后移,每次判断是否两个指针值相同
编程之美上:
判断两个链表最后一个结点是否相同,
时间复杂度O(L1+L2)
检测两个链表是否相交,(返回第一个公共结点,),检测一个链表是否有环(包括循环链表和尾环链表)问题的总结。
问题1:检测一个单链表是否有环:
方法1: hash表
遍历的同时,对结点的地址值建立一个hash table(具体为插入操作,处理collision):每次访问一个结点,查找hash表,如果找不到,插入,否则返回结果,有环。遍历直到访问结束。
之前还考虑过同一个value和同义词怎么区分,对hash概念模糊,看了某大神的hash查找代码后顿时豁然开朗,完全不用考虑这个问题。通过一个while循环返回的指针是否为空来区分。
方法2:bool数组
初始化一个较大bool数组,赋值为false, 每次访问一个结点,如果对应bool数组值为false,改为true,否则,返回结果有环。遍历直到访问结束。
方法3:倒置链表(该方法仅能检测循环链表)
倒置链表,pprev,p,pnext,每次判断pnext是否为head 如果出现,返回结果,有环。
由于破坏了链表结构,需要再倒置一次
方法4:快慢指针(面试官需要的算法)
设置fast slow指针,fast走两步,slow走一步。分析后面再看
问题1补充:如果还需返回第一个环的入口结点?
从相遇结点,和head两个位置同时向后遍历,第一次相遇的点即为环入口结点。
m=Nnonloop-1+r2*Nloop+Iloopmeetindex -------(2)
(1)-(2): m=(r1-r2)Nloop -----(3) 其中,r1-r2>=1, m>=1
由(2) (3):
(r1-2r2)Nloop=Nnonloop-1+Iloopmeetindex ------(4)
我们要证明:
Nnonloop=r3*Nloop+ (Nnonloop+Nloop-(Iloopmeetindex+Nnonloop-1))
=r3*Nloop+ (Nloop-Iloopmeetindex+1) -----------(5)
从(4)移项发现:
Nnonloop=(r1-2*r2)+1-Iloopmeetindex ------(6)
其中r1-2*r2>=1,即能找到一个r3使得r3+1>=1,因此得证。
问题2:检测两个单链表是否相交(12年CS考研最后一题,微软面试题):
方法1:分别遍历两个链表,长度分别为L1,L2,然后较长链表指针后移|L1-L2|长度,然后两个指针同时后移,每次判断是否相同
当年考研我写的答案,这个方法还可以返回首个公共结点,如果不用的话,时间复杂度比编程之美的长一些
方法2:分别遍历两个链表,长度分别为L1,L2,记录两个尾结点(编程之美的答案,还未验证)。缺陷是不能返回首个公共结点。
方法3:还是hash表
对一个遍历,同时建立hash表,然后对另一个遍历,同时查hash表
方法4:将两个link首尾相连
如果相交,必出现环,再用检测环来检测
并且情况可以分为两种,一种是公共结点在环外面,一种是在环内。
都已经思考到这一步了,结果都没想到好的解决方案,最后还是想到一个笨得hash方法。后来看了July大神给的答案,又一次豁然开朗= =
先检测其中一个是否有环,如果有的话,判断环内相遇的结点(fast slow指针法)是否在另一个链表出现,因为如果两个链表中有环,相交的的话一定公用环的所有结点,只需检测一个中环内结点是否在另一个链表即可得出结论。
觉得自己有时候思考问题到一定程度了,连简单的都想不到= =
这篇帖子真的脱了好久,主要是关于那段理论的证明,以及最后有环判交方法的思考= =
判断两个单链表是否相交:
我写的:
遍历Link1,O(L1)
遍历Link2,O(L2)
将长的链表指针后移|L2-L1|个长度,然后两个指针逐个后移,每次判断是否两个指针值相同
时间复杂度O(L1+L2+max(L1,L2))
PS:记得后来在admis实验室我的位子上,还和if和炮哥两位大神讨论过这个题目- -
编程之美上:
判断两个链表最后一个结点是否相同,
时间复杂度O(L1+L2)
检测两个链表是否相交,(返回第一个公共结点,),检测一个链表是否有环(包括循环链表和尾环链表)问题的总结。
问题1:检测一个单链表是否有环:
方法1: hash表
遍历的同时,对结点的地址值建立一个hash table(具体为插入操作,处理collision):每次访问一个结点,查找hash表,如果找不到,插入,否则返回结果,有环。遍历直到访问结束。
之前还考虑过同一个value和同义词怎么区分,对hash概念模糊,看了某大神的hash查找代码后顿时豁然开朗,完全不用考虑这个问题。通过一个while循环返回的指针是否为空来区分。
方法2:bool数组
初始化一个较大bool数组,赋值为false, 每次访问一个结点,如果对应bool数组值为false,改为true,否则,返回结果有环。遍历直到访问结束。
方法3:倒置链表(该方法仅能检测循环链表)
倒置链表,pprev,p,pnext,每次判断pnext是否为head 如果出现,返回结果,有环。
由于破坏了链表结构,需要再倒置一次
方法4:快慢指针(面试官需要的算法)
设置fast slow指针,fast走两步,slow走一步。分析后面再看
问题1补充:如果还需返回第一个环的入口结点?
从相遇结点,和head两个位置同时向后遍历,第一次相遇的点即为环入口结点。
关于这个的理论基础简要说明如下:
notations:
m: 两个指针移动得次数
Nnonloop:非环部分的长度(结点个数)
Nloop:环部分的长度(结点个数)
Iloopmeetindex: fast slow指针环内相遇的位置,用环内从环头为1开始的index
r1,r2,r3均为不小于0的整数
m=Nnonloop-1+r2*Nloop+Iloopmeetindex -------(2)
(1)-(2): m=(r1-r2)Nloop -----(3) 其中,r1-r2>=1, m>=1
由(2) (3):
(r1-2r2)Nloop=Nnonloop-1+Iloopmeetindex ------(4)
我们要证明:
Nnonloop=r3*Nloop+ (Nnonloop+Nloop-(Iloopmeetindex+Nnonloop-1))
=r3*Nloop+ (Nloop-Iloopmeetindex+1) -----------(5)
从(4)移项发现:
Nnonloop=(r1-2*r2)+1-Iloopmeetindex ------(6)
其中r1-2*r2>=1,即能找到一个r3使得r3+1>=1,因此得证。
问题2:检测两个单链表是否相交(12年CS考研最后一题,微软面试题):
方法1:分别遍历两个链表,长度分别为L1,L2,然后较长链表指针后移|L1-L2|长度,然后两个指针同时后移,每次判断是否相同
当年考研我写的答案,这个方法还可以返回首个公共结点,如果不用的话,时间复杂度比编程之美的长一些
方法2:分别遍历两个链表,长度分别为L1,L2,记录两个尾结点(编程之美的答案,还未验证)。缺陷是不能返回首个公共结点。
方法3:还是hash表
对一个遍历,同时建立hash表,然后对另一个遍历,同时查hash表
方法4:将两个link首尾相连
如果相交,必出现环,再用检测环来检测
问题2补充:如果两个链表可能是有环的链表,怎么判?
并且情况可以分为两种,一种是公共结点在环外面,一种是在环内。
都已经思考到这一步了,结果都没想到好的解决方案,最后还是想到一个笨得hash方法。后来看了July大神给的答案,又一次豁然开朗= =
先检测其中一个是否有环,如果有的话,判断环内相遇的结点(fast slow指针法)是否在另一个链表出现,因为如果两个链表中有环,相交的的话一定公用环的所有结点,只需检测一个中环内结点是否在另一个链表即可得出结论。
觉得自己有时候思考问题到一定程度了,连简单的都想不到= =
这篇帖子真的脱了好久,主要是关于那段理论的证明,以及最后有环判交方法的思考= =