对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:
你能给出不利用额外空间的解法么?
public ListNode detectCycle(ListNode head) { if(head==null){ return null; } ListNode fast=head; ListNode slow=head; while(fast!=null&&fast.next!=null){ fast=fast.next.next; slow= slow.next; if(slow==fast){ slow=head; while(fast!=slow){ slow=slow.next; fast=fast.next; } return slow; } } return null; }
求助:为啥对快指针的赋值需要从第二个开始?
如果我对快慢指针的赋值是:
ListNode slow = head.; // 慢指针 ListNode fast = head.next; // 快指针
就提示运行超时,但是如果是下面的这种就是可以的。这是为啥啊?求大佬指点一下!
下面这个代码是可以通过的
public ListNode detectCycle(ListNode head) { if(head == null || head.next == null) return null; ListNode slow = head.next; // 慢指针 ListNode fast = head.next.next; // 快指针 while(fast != null && fast.next != null){ if(fast == slow) { //有环 while(head != slow){ //从头再来 head = head.next; slow = slow.next; } return head; } slow = slow.next; fast = fast.next.next; } return null; }
public class Solution { public ListNode detectCycle(ListNode head) { if(head==null || head.next==null) return null; ListNode l1=head,l2=head; int i=0; while(l2!=null && l2.next!=null){ l1=l1.next; l2=l2.next.next; i++; if (l1==l2){ l1=head; while(l1!=l2){ l1=l1.next; l2=l2.next; } return l1; } } return null; } }双指针
public class Solution { public ListNode detectCycle(ListNode head) { if (head == null) { return null; } //判断是否有环 ListNode meetNode = meetingNode(head); if (meetNode == null) {//说明无环 return null; } //计算环的大小 ListNode fast = meetNode; ListNode slow = meetNode; int roll=0; do { fast = fast.next; roll++; }while (slow != fast); //fast先走roll-1步,然后shlow走,直到他们相遇,即为入口 slow = head; fast = head; while(roll>0) { roll--; fast=fast.next; } while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; } //寻找相遇节点,如果无环,返回null public ListNode meetingNode(ListNode head) { ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { return slow; } } return null; } }
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle(ListNode head) { if(head==null) return null; ListNode meetNode=meetingNode(head); if(meetNode==null)return null; ListNode fast=head; ListNode low=meetNode; while(fast!=low){ fast=fast.next; low=low.next; } return low; } public ListNode meetingNode(ListNode head){ ListNode fast=head; ListNode low=head; while(fast!=null&&fast.next!=null) { fast=fast.next.next; low=low.next; if(low==fast)return low; } return null; } }
import java.util.*; public class Solution { public ListNode detectCycle(ListNode head) { if (head == null) { return null; } Set<ListNode> set = new HashSet<>(); set.add(head); while (head.next!= null) { head = head.next; if (set.contains(head)){ return head; } set.add(head); } return null; } }
环儿的入口结点:从head起,第一个在环儿里的结点。 思路:爱的暴力转圈圈,时间复杂度O((n-m)*m),n=链表长度,m=环的长度;最坏接近O(n^2) 1)定义一对快慢指针,先让两个指针进入环中。 若指针走的过程中转角遇到空null结点,说明没有环,return null即可。唉!没找到爱的圈圈。 2)两个指针进入环中相遇后,进入下一步找环入口操作: 从head依次往后枚举判断当前枚举的结点是否在环中,判断方法: 让环中指针在环内转圈,若途中遇到了当前枚举的结点,说明该结点在环中。 找到第一个这样的结点就是入口结点。
public ListNode detectCycle(ListNode head) { if(head!=null){ ListNode first=head,second=head.next,start;//定义指针 //尝试把指针拉入环中 while(first!=second){ if(first==null||second==null||second.next==null) return null;//没环 first=first.next; second=second.next.next; } //有环 //找环入口:从head起依次往后枚举,第一个在环里的结点就是环的入口结点 start=second;//标记环起点 first=head; while(first!=null){ //second指针在环里转一圈,查看当前结点first是否在环里 do{ if(second==first) return first;//找到的第一个就是结果 second=second.next; }while(second!=start);//转一圈退出 first=first.next;//枚举下一个 } return null; } return null; }
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle(ListNode head) { if(head == null || head.next == null){ return null; } ListNode slow = head; ListNode fast = head; while(fast.next!=null && fast.next.next!=null){ slow = slow.next; fast = fast.next.next; if(fast == slow){ slow = head; while(slow!=fast) { slow = slow.next; fast = fast.next; } break; } } if(fast.next == null || fast.next.next == null){ return null;} return slow; } }
public class Solution { public ListNode detectCycle(ListNode head) { // first get the length of the circel // use fast and slow pointer //how to get the length?first meet the try again count if(head == null||head.next == null) return null; int len = 1; ListNode slow = head; ListNode fast = head.next; ListNode temp; ListNode res = head; while(slow!=null&&fast!=null){ slow = slow.next; fast = fast.next; if(fast!=null){ fast = fast.next; } if(fast == slow) break; } if(fast==null||slow==null) return null; temp = slow; while(slow.next!=temp){ slow = slow.next; len++; } for(int i = 0;i<len;i++){ res = res.next; } while(head!=res){ head = head.next; res = res.next; } return res; } }
//思路:和判断是否有环解法一致,将遍历后的节点指向一个新增节点,如果遍历过程中,某个节点指向了那个节点,那么这个节点就是入口节点(即交叉点)。
public static ListNode detectCycle(ListNode head) { ListNode target = new ListNode(-1); ListNode cur = head; while(cur != null) { if(cur.next == target) { return cur; } ListNode next = cur.next; cur.next = target; cur = next; } return null; }
public ListNode detectCycle(ListNode head) { if (head==null) return null; //1.使用快慢指针方法,判定是否存在环 //2.将两指针分别放在链表头(X)和相遇位置(Z),并改为相同速度推进,则两指针在环开始位置相遇(Y)。 //3.证明:首先a是起点到环的距离 b是环起点到相遇点的距离 c是相遇点到环起点的距离 //2*(a + b) = a + b + n * (b + c); a=(n - 1) * b + n * c = (n - 1)(b + c) +c; //即a = c; 下面i是慢指针 j是快指针 不涉及插入 所以不用设置哑头节点 ListNode i = head,j = head; //j.next.next存在前提j.next存在 再者 要判断链表是否有尽头 仅仅看j下一步是不是空即可 i走的慢可以不管 while (j.next!=null&&j.next.next!=null){ //不能一上来就移动 这样i==j直接触发了 gg //不相等就快慢指针 分别行动直到i==j相遇再进行相应处理 i = i.next; j = j.next.next; if (i==j) { ListNode temp = head; //i和j点相遇 //起点位置和环位置同时每次走一步 一定会在环起点相遇 上面证明了a=c while (temp!=i){ temp = temp.next; i = i.next; } //指向头节点的指针和指向相遇点的指针都相等了 说明在环起点相遇了 返回相遇节点值 return temp; } } return null; }
/** 思路: 假定快慢指针,相同时间下,快指针所走路程是慢指针的两倍 当两个指针在环上相遇时,快指针比慢指针多走了n圈 减去二者在环上重叠的部分,快指针多走的距离即是直线的长度; 故此时只需要将慢指针从头走起,快指针变为慢指针继续前进,二者定会在环入口相遇 * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle(ListNode head) { if (head == null || head.next == null || head.next.next == null) { return null; } ListNode p1 = head; ListNode p2 = head; int step = 0; do { step++; p1 = p1.next; p2 = p2.next.next; } while (p1 != p2 && p2 != null && p2.next != null); if (p2 == null || p2.next == null) { return null; } p1 = head; while (p1 != p2) { p1 = p1.next; p2 = p2.next; } return p1; } }
public class Solution { public ListNode detectCycle(ListNode head) { if(head==null) return null; while(head.next!=null){ if(head.next==head) return head; ListNode r=head.next; head.next=head; head=r; } return null; } } /** 假设X,Y,Z分别为链表起始位置,环开始位置和两指针相遇位置,则根据快指针速度为慢指针速度的两倍,可以得出: 2*(a + b) = a + b + n * (b + c);即 a=(n - 1) * b + n * c = (n - 1)(b + c) +c; 注意到b+c恰好为环的长度,故可以推出,如将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。 故两指针会在环开始位置相遇。 */ public class Solution { public ListNode detectCycle(ListNode head) { if(head==null) return null; ListNode slow=head; ListNode fast=head; while(fast!=null&&fast.next!=null){ slow=slow.next; fast=fast.next.next; if(slow==fast){//相遇位置 while(head!=slow){ head=head.next; slow=slow.next; } return head; } } return null; } }
public class Solution { public ListNode detectCycle(ListNode head) { if(head==null||head.next==null) return null; ListNode fast = head; ListNode slow = head; //先找出相遇的位置 while(fast!=null&&fast.next!=null){ fast = fast.next.next; slow = slow.next; //相遇了则跳出,此时slow==fast相遇 if(slow==fast) break; } //不相等说明无循环 if(fast!=slow) return null; //慢指针重新指向首部,快指针指向相遇节点,再次循环(速度一致) //再次相遇时是在循环的入口节点 slow = head; while(slow!=fast){ slow = slow.next; fast = fast.next; } return fast; } }
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ // 思路:先判断有没有环。在有环的情况下,再找环的入口。 public class Solution { public ListNode detectCycle(ListNode head) { if(head == null){ return head; } ListNode fast, slow; fast = slow = head; boolean flag = false; while(fast != null && fast.next != null){ fast = fast.next.next; slow = slow.next; if(fast == slow){ flag = true; break; } } if(flag == false){ return null; } slow = head; while(slow != fast){ slow = slow.next; fast = fast.next; } return slow; } }
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode detectCycle(ListNode head) { ListNode fast = head; ListNode slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; if (fast == slow) { break; } } if (fast == null || fast.next == null) { return null; } slow = head; while (fast != null && slow != null) { if (fast == slow) { return fast; } fast = fast.next; slow = slow.next; } return null; } }
public class Solution { public ListNode detectCycle(ListNode head) { if(head == null || head.next == null) return null; ListNode slow=head,fast=head; while(fast.next!=null && fast.next.next!=null){ slow=slow.next; fast=fast.next.next; if(slow==fast){ ListNode cur = head; while(cur!=slow){ cur=cur.next; slow=slow.next; } return cur; } } return null; } }