寻找单向链表中含有环的入口节点
来源:互联网 发布:vps建站 编辑:程序博客网 时间:2024/05/29 07:36
这是一个比较基本的链表问题。总结一下,可以扩展为以下几类问题:
- 判断链表中是否有环
- 求链表中环的长度
- 求环的入口节点的位置
- 带环链表的长度
解法:
- 判断是否有环:
- 可以利用快慢指针追赶的方式,即设定两个指针,slow、fast,slow指针每次走一步,fast指针每次走两步,如果存在环,则两个指针会相遇,即slow.val==fast.val;如果不存在环,则fast指针会先于slow到达链表结尾,此时,fast 应该为null,循环结束。
- 为什么有环的情况下二者一定会相遇:
- 因为fast会先于slow进入环,在slow进入环之后,可以把slow看作在前面,如果slow在前面,fast在后面每次循环都会向slow靠近1,所以一定会相遇,而不会出现fast直接跳过slow的情况。
具体代码如下:
定义ListNode数据结构
public class ListNode { public int val; public ListNode next; public ListNode(int x) { val = x; }
/** * 判断单向链表是否有环 * @param pHead * @return */ public boolean HasLoopInListNode(ListNode pHead){ if(pHead == null ||pHead.next ==null){ return false; } ListNode slow = pHead; ListNode fast = pHead; while(slow !=null&&fast.next !=null){ //快慢指针分别访问下一节点 slow = slow.next; fast = fast.next.next; if(fast.val == slow.val) return true; } return false; }
- 求环的长度
- 对于求环的长度,可以在第一问的基础上进行进一步的操作,即记录下快慢指针slow、fast首次相遇的节点P,然后slow从P点开始,再次访问环中下一节点,而fast停留在碰撞点P,直到slow再一次到达碰撞点P,slow走过的步数即为环的长度。
/** * 求环的长度 * @param pHead * @return */ public int LengthOfLoopListNode(ListNode pHead){ if(pHead == null ||pHead.next ==null){ return 0; } ListNode slow = pHead; ListNode fast = pHead; //记录快慢指针第一次相遇之后为起点,直至第二次相遇所走过的步长 int step = 0; while(slow !=null&&fast.next !=null){ slow = slow.next; fast = fast.next.next; if(fast.val == slow.val){ break; } } if(fast==null||fast.next == null){ return step; } //此时,fast停留在首次碰撞的节点 while(fast.val != slow.next.val){ step++; slow = slow.next; } return step; }
- 求环的连接点在哪里
- 关于求连接点的问题,可以在第二问的基础上再进一步分析,因为在第二问求解过程中,记录了fast与slow首次相遇的节点P,可称之为碰撞点P(点P可能是在环的内部,也可能正好在连接点)。碰撞点P到环连接点的距离,就是头指针到连接点的距离。定理证明如下:
-
假设某含有环的链表如上图所示,X为头结点,Y为环的连接点,Z为快慢指针首次相遇的点。
则在快慢指针首次相遇时,- slow走过的距离:L1 = a+b;
- fast 走过的距离:L2 = a+b+c+b。
又因为fast的速度是slow的两倍,所以fast走过的距离是slow走过的两倍,所以,L2 = 2*L1。即有2(a+b) = a+b+c+b。很容易得出,a = c,也就是说,头指针到连接点的距离,就是快慢指针首次相遇的碰撞点到连接点的距离。
所以在求连接点位置这个问题时,已经在第二问中求出了碰撞点P的位置(图中为Z),则可以让slow从头结点开始,fast从碰撞点Z开始,每次分别走一步,直至相遇,因为a=c,所以相遇时,一定在连接点Y处
/** * 找出连接点 * @param pHead * @return */ public ListNode getFirstJoin(ListNode pHead){ if(pHead == null ||pHead.next ==null){ return null; } ListNode slow = pHead; ListNode fast = pHead; //找出第一次碰撞的点 while(slow !=null&&fast.next !=null){ slow = slow.next; fast = fast.next.next; if(fast.val == slow.val){ break; } } slow = pHead; while(slow.val != fast.val){ slow = slow.next; fast = fast.next; } return slow; }
- 求带环链表长度
- 此问稍作分析即可得到带环链表长度L =a+ b+c
- 因为在第三问中,可以设置一个变量Len记录头结点到连接点的距离,换长度可以在第二问中求出。
/** * 求带环链表长度 * @param pHead * @return */ public int getLoopLength(ListNode pHead){ if(pHead == null ||pHead.next ==null){ return 0; } ListNode slow = pHead; ListNode fast = pHead; //头结点到连接点的距离 int LengthToJoin = 0; //环长度 int LengthOfLoop = LengthOfLoopListNode(pHead); //找出第一次碰撞的点 while(slow !=null&&fast.next !=null){ slow = slow.next; fast = fast.next.next; if(fast.val == slow.val){ break; } } slow = pHead; while(slow.val != fast.val){ LengthToJoin++; slow = slow.next; fast = fast.next; } return LengthOfLoop+LengthToJoin; }
0 0
- 寻找单向链表中含有环的入口节点
- 寻找有环单链表的入口节点
- 判断链表是否含有环,若有则找出环的入口节点
- 寻找单向链表的倒数第k个节点
- 单向链表相交的第一个公共结点, 判断链表是否有环以及环的入口节点
- 单链表寻找环的入口点
- 单链表寻找环,寻找环的入口点
- 寻找环入口
- 单向还链表如何寻找起始节点
- 题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。
- 寻找带环的单链表的换的入口位置处的节点
- 判断单向链表中是否有环和查找环的入口
- 链表中环的入口节点
- 链表中环的入口节点
- 链表中环的入口节点
- 链表中环的入口节点
- 链表中环的入口节点
- 链表中环的入口节点
- HDU1009 不明错误
- Neutron总结-iptables基础操作之查看操作
- js引用<select>下拉列表选定的内容
- Scala里面的break
- Android-drawable
- 寻找单向链表中含有环的入口节点
- move_base导航的源码心得
- java restful api 介绍
- import项目找不到maven 依赖包的处理方法
- Sum—LeetCode-43 Multiply Strings
- 分库实现
- ASP.NET MVC5 + EF6 入门教程 (5) Model和Entity Framework
- jsp自定义标签:body-content取值的含义
- 二叉树的深度优先遍历(DFS)与广度优先遍历(BFS)