给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
数据范围: ,
要求:空间复杂度 ,时间复杂度
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:
可以看到环的入口结点的结点值为3,所以返回结点值为3的结点。
输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表
返回链表的环的入口结点即可,我们后台程序会打印这个结点对应的结点值;若没有,则返回对应编程语言的空结点即可。
{1,2},{3,4,5}
3
返回环形链表入口结点,我们后台程序会打印该环形链表入口结点对应的结点值,即3
{1},{}
"null"
没有环,返回对应编程语言的空结点,后台程序会打印"null"
{},{2}
2
环的部分只有一个结点,所以返回该环形链表入口结点,后台程序打印该结点对应的结点值,即2
C++版: class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { ListNode*fast=pHead,*low=pHead; while(fast&&fast->next){ fast=fast->next->next; low=low->next; if(fast==low) break; } if(!fast||!fast->next)return NULL; low=pHead;//low从链表头出发 while(fast!=low){//fast从相遇点出发 fast=fast->next; low=low->next; } return low; } };
java版: public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { ListNode fast=pHead; ListNode low=pHead; while(fast!=null&&fast.next!=null){ fast=fast.next.next; low=low.next; if(fast==low) break; } if(fast==null||fast.next==null) return null; low=pHead; while(fast!=low){ fast=fast.next; low=low.next; } return low; } }
public class Solution { ListNode EntryNodeOfLoop(ListNode pHead){ if(pHead == null || pHead.next == null) return null; ListNode p1 = pHead; ListNode p2 = pHead; while(p2 != null && p2.next != null ){ p1 = p1.next; p2 = p2.next.next; if(p1 == p2){ p2 = pHead; while(p1 != p2){ p1 = p1.next; p2 = p2.next; } if(p1 == p2) return p1; } } return null; } }
http://kekecv.com/2016/06/08/Linked-List-Cycle-%E5%88%A4%E6%96%AD%E9%93%BE%E8%A1%A8%E6%98%AF%E5%90%A6%E6%9C%89%E7%8E%AF%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%E7%8E%AF%EF%BC%8C%E6%89%BE%E5%88%B0%E7%8E%AF%E7%9A%84%E5%85%A5%E5%8F%A3/
当快慢指针相遇的时候:
此时慢指针走的路程为Sslow =
x + m * c + a
快指针走的路程为Sfast = x + n * c + a
2 Sslow =
Sfast
2 * ( x + m*c + a ) = (x + n *c + a)
从而可以推导出:
x = (n
- 2 * m )*c - a
= (n - 2 *m -1 )*c + c - a
即环前面的路程 =
数个环的长度(为可能为0) + c - a
什么是c - a?这是相遇点后,环后面部分的路程。(橙色路程)
所以,我们可以让一个指针从起点A开始走,让一个指针从相遇点B开始继续往后走,
2个指针速度一样,那么,当从原点的指针走到环入口点的时候(此时刚好走了x)
从相遇点开始走的那个指针也一定刚好到达环入口点。
所以2者会相遇,且恰好相遇在环的入口点。
最后,判断是否有环,且找环的算法复杂度为:
时间复杂度:O(n)
publicclassSolution {publicListNode EntryNodeOfLoop(ListNode pHead){///if(pHead==null|| pHead.next==null|| pHead.next.next==null)returnnull;ListNode fast=pHead.next.next;ListNode slow=pHead.next;/////先判断有没有环while(fast!=slow){if(fast.next!=null&& fast.next.next!=null){fast=fast.next.next;slow=slow.next;}else{//没有环,返回returnnull;}}//循环出来的话就是有环,且此时fast==slow.fast=pHead;while(fast!=slow){fast=fast.next;slow=slow.next;}returnslow;}}
publicclassSolution {publicListNode EntryNodeOfLoop(ListNode pHead){if(pHead==null|| pHead.next==null)returnnull;ListNode fast=pHead.next;ListNode slow=pHead;while(fast!=null){slow.next=null;slow=fast;fast=fast.next;}returnslow;}}
if(head==null) return null; ListNode fastNode = head; ListNode slowNode = head; while(true){ if((fastNode.next!=null)&&(fastNode.next.next!=null)){ fastNode = fastNode.next.next; slowNode = slowNode.next; }else return null; if(fastNode == slowNode) break; } fastNode = head; while(true){ if(fastNode==slowNode) break; fastNode = fastNode.next; slowNode = slowNode.next; } return slowNode;
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { // 时间复杂度O(N),空间复杂度O(1) if (pHead == nullptr) return nullptr; ListNode *slow = pHead, *fast = pHead; while (fast->next && fast->next->next) { slow = slow->next; fast = fast->next->next; if (fast == slow) { fast = pHead; while (fast != slow) { fast = fast->next; slow = slow->next; } return fast; } } return nullptr; } };
ListNode *EntryNodeOfLoop(ListNode *pHead) { while (pHead) { if (pHead->val > 10000) { pHead->val = pHead->val - 10000; return pHead; } pHead->val = pHead->val + 10000; pHead = pHead->next; if (pHead == nullptr) return nullptr; } return nullptr; }
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead ) { struct ListNode*p = pHead; struct ListNode*q = pHead; if(pHead == NULL) { printf("null"); return NULL; } while(p != NULL&&p->next!=NULL) { p = p->next->next;//快慢指针判断是否有环,p走两步,q走一步 q = q->next; if(q == p)//相遇证明有环,并且记录这个结点 { p = pHead;//一个结点回到头结点,另外一个留在相遇的位置 while(p!=NULL && p->next!=NULL) { if(q == p)//当p与q相遇时,这个地方就是循环结点入口! { printf("%d",p->val); return p; } p = p->next;//p,q都一步一步走 q = q->next; } } } printf("null"); return NULL; }
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } }; */ class Solution{ public: ListNode* EntryNodeOfLoop(ListNode* pHead) { set<ListNode*> s; while(pHead!=NULL) { if(s.find(pHead)!=s.end()) return pHead; s.insert(pHead); pHead=pHead->next; } return pHead; } };
public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { ListNode fast = pHead; ListNode slow = pHead; 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 = pHead; while (fast != slow){ fast = fast.next; slow = slow.next; } return slow; } }
public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { while(pHead!=null){ if(pHead.val>10000){ pHead.val-=10000; return pHead; } else{ pHead.val+=10000; pHead=pHead.next; } } return null; } }
public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { /* ListNode s=pHead,q=pHead;//常规快慢指针 while(s!=null&&q!=null){ s=s.next; if(q.next==null) return null; q=q.next.next; if(s==q) { ListNode p=pHead; while(p!=s){ p=p.next; s=s.next; } return p; } } if(q!=s) return null; return s; */ while(pHead!=null){ //垃圾快速解法 只适用特定条件 if(pHead.val<0){ pHead.val=-pHead.val; return pHead; } pHead.val=-pHead.val; pHead=pHead.next; } return null; } }
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } } */ import java.util.*; public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { Set set = new HashSet<Integer>();//声明集合存放节点循环的值 ListNode res = null; if(pHead.next == null)return null; while(pHead != null){ if(set.add(pHead.val)){//如果存在重复的元素就是需要找的公共节点,此时就可以返回该对象 pHead = pHead.next; }else break; } return pHead; } }
public ListNode EntryNodeOfLoop(ListNode pHead) { int num = 10001; ListNode p = pHead; while (p != null) { if (p.val >= num) { p.val = p.val - num; return p; } p.val = p.val + num; p = p.next; } return null; }
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { if (pHead==nullptr) return pHead; map<int, int> p; int i=0; while(!p.count(pHead->val) && pHead->next!=nullptr) { p.insert(pair<int, int>(i,pHead->val)); i++; pHead=pHead->next; } if(pHead->next==nullptr) return nullptr; return pHead; } };
function EntryNodeOfLoop(pHead) { // write code here if (pHead.next === null) return null const map = new Map() let currentNode = pHead while(currentNode) { if (map.has(currentNode)) return currentNode else map.set(currentNode, currentNode) currentNode = currentNode.next } return null }
public ListNode EntryNodeOfLoop(ListNode pHead) { if(pHead == null || pHead.next == null){ return null; } HashSet<ListNode> nodeSet = new HashSet<>(); while(pHead != null){ if(!nodeSet.add(pHead)){ return pHead; } pHead = pHead.next; } return null; }
当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。