日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

链表中环的入口结点 python_链表中环的入口结点

發(fā)布時間:2025/3/20 python 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 链表中环的入口结点 python_链表中环的入口结点 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

117

推薦

編輯于 2015-08-25 11:27:14

回復(fù)(43)

287

思路:

設(shè)置快慢指針,都從鏈表頭出發(fā),快指針每次走兩步,慢指針一次走一步,假如有環(huán),一定相遇于環(huán)中某點(diǎn)(結(jié)論1)。接著讓兩個指針分別從相遇點(diǎn)和鏈表頭出發(fā),兩者都改為每次走一步,最終相遇于環(huán)入口(結(jié)論2)。以下是兩個結(jié)論證明:

兩個結(jié)論:

1、設(shè)置快慢指針,假如有環(huán),他們最后一定相遇。

2、兩個指針分別從鏈表頭和相遇點(diǎn)繼續(xù)出發(fā),每次走一步,最后一定相遇與環(huán)入口。

證明結(jié)論1:設(shè)置快慢指針fast和low,fast每次走兩步,low每次走一步。假如有環(huán),兩者一定會相遇(因?yàn)閘ow一旦進(jìn)環(huán),可看作fast在后面追趕low的過程,每次兩者都接近一步,最后一定能追上)。

證明結(jié)論2:

設(shè):

鏈表頭到環(huán)入口長度為--a

環(huán)入口到相遇點(diǎn)長度為--b

相遇點(diǎn)到環(huán)入口長度為--c

則:相遇時

快指針路程=a+(b+c)k+b ,k>=1? 其中b+c為環(huán)的長度,k為繞環(huán)的圈數(shù)(k>=1,即最少一圈,不能是0圈,不然和慢指針走的一樣長,矛盾)。

慢指針路程=a+b

快指針走的路程是慢指針的兩倍,所以:

(a+b)*2=a+(b+c)k+b

化簡可得:

a=(k-1)(b+c)+c 這個式子的意思是: 鏈表頭到環(huán)入口的距離=相遇點(diǎn)到環(huán)入口的距離+(k-1)圈環(huán)長度。其中k>=1,所以k-1>=0圈。所以兩個指針分別從鏈表頭和相遇點(diǎn)出發(fā),最后一定相遇于環(huán)入口。 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從鏈表頭出發(fā)

while(fast!=low){//fast從相遇點(diǎn)出發(fā)

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;

}

}

編輯于 2019-12-04 12:29:55

回復(fù)(46)

336

【轉(zhuǎn)】

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/

假設(shè)x為環(huán)前面的路程(黑色路程),a為環(huán)入口到相遇點(diǎn)的路程(藍(lán)色路程,假設(shè)順時針走), c為環(huán)的長度(藍(lán)色+橙色路程)

當(dāng)快慢指針相遇的時候:

此時慢指針走的路程為Sslow =

x + m * c + a

快指針走的路程為Sfast = x + n * c + a

2 Sslow =

Sfast

2 * ( x + m*c + a ) = (x + n *c + a)

從而可以推導(dǎo)出:

x = (n

- 2 * m )*c - a

= (n - 2 *m -1 )*c + c - a

即環(huán)前面的路程 =

數(shù)個環(huán)的長度(為可能為0) + c - a

什么是c - a?這是相遇點(diǎn)后,環(huán)后面部分的路程。(橙色路程)

所以,我們可以讓一個指針從起點(diǎn)A開始走,讓一個指針從相遇點(diǎn)B開始繼續(xù)往后走,

2個指針?biāo)俣纫粯?#xff0c;那么,當(dāng)從原點(diǎn)的指針走到環(huán)入口點(diǎn)的時候(此時剛好走了x)

從相遇點(diǎn)開始走的那個指針也一定剛好到達(dá)環(huán)入口點(diǎn)。

所以2者會相遇,且恰好相遇在環(huán)的入口點(diǎn)。

最后,判斷是否有環(huán),且找環(huán)的算法復(fù)雜度為:

時間復(fù)雜度:O(n)

空間復(fù)雜度:O(1)

下面的是斷鏈法。不過題目要求不允許修改鏈表時就尷尬了。

編輯于 2017-03-11 10:47:33

回復(fù)(67)

379

第一步,找環(huán)中相匯點(diǎn)。分別用p1,p2指向鏈表頭部,p1每次走一步,p2每次走二步,直到p1==p2找到在環(huán)中的相匯點(diǎn)。

第二步,找環(huán)的入口。接上步,當(dāng)p1==p2時,p2所經(jīng)過節(jié)點(diǎn)數(shù)為2x,p1所經(jīng)過節(jié)點(diǎn)數(shù)為x,設(shè)環(huán)中有n個節(jié)點(diǎn),p2比p1多走一圈有2x=n+x;

n=x;可以看出p1實(shí)際走了一個環(huán)的步數(shù),再讓p2指向鏈表頭部,p1位置不變,p1,p2每次走一步直到p1==p2;

此時p1指向環(huán)的入口。

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;

}

}

發(fā)表于 2015-09-15 15:23:04

回復(fù)(65)

65

HashSet set = new HashSet();

while (pHead != null) {

if (!set.add(pHead)) {

return pHead;

}

pHead = pHead.next;

}

returnnull;

發(fā)表于 2015-10-07 12:45:55

回復(fù)(34)

32

//左神講的

//先說個定理:兩個指針一個fast、一個slow同時從一個鏈表的頭部出發(fā)

//fast一次走2步,slow一次走一步,如果該鏈表有環(huán),兩個指針必然在環(huán)內(nèi)相遇

//此時只需要把其中的一個指針重新指向鏈表頭部,另一個不變(還在環(huán)內(nèi)),

//這次兩個指針一次走一步,相遇的地方就是入口節(jié)點(diǎn)。

//這個定理可以自己去網(wǎng)上看看證明。

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;

fast = pHead;

while(fast != slow){

fast = fast.next;

slow = slow.next;

}

return fast;

}

}

發(fā)表于 2017-08-17 11:29:22

回復(fù)(13)

114

/*

時間復(fù)雜度為O(n),兩個指針,一個在前面,另一個緊鄰著這個指針,在后面。

兩個指針同時向前移動,每移動一次,前面的指針的next指向NULL。

也就是說:訪問過的節(jié)點(diǎn)都斷開,最后到達(dá)的那個節(jié)點(diǎn)一定是尾節(jié)點(diǎn)的下一個,

也就是循環(huán)的第一個。

這時候已經(jīng)是第二次訪問循環(huán)的第一節(jié)點(diǎn)了,第一次訪問的時候我們已經(jīng)讓它指向了NULL,

所以到這結(jié)束。

*/

class Solution {

public:

ListNode* EntryNodeOfLoop(ListNode* pHead)

{

if (!pHead->next)

return NULL;

ListNode* previous = pHead;

ListNode* front = pHead ->next;

while (front)

{

previous->next = NULL;

previous = front;

front = front->next;

}

return previous;

}

};

編輯于 2016-01-26 16:36:01

回復(fù)(39)

15

class Solution {

public:

ListNode* EntryNodeOfLoop(ListNode* pHead)

{

set s;

ListNode* node = pHead;

while(node!=NULL){

if(s.insert(node).second)

node = node->next;

else

return node;

}

return node;

}

};

我這里用到了STL中的set,set有一個特性就是不能插入相同元素,這樣只需遍歷原List一次就可以判斷出有沒有環(huán),還有環(huán)的入口地址。s.insert(node).second這里在插入的同時也判斷了插入是否成功,如果不成功表明set中已經(jīng)有該元素了,該元素就是環(huán)的入口元素。

發(fā)表于 2016-07-23 18:20:48

回復(fù)(7)

30

python solution: # -*- coding:utf-8 -*-

# class ListNode:

# def __init__(self, x):

# self.val = x

# self.next = None

class Solution:

def EntryNodeOfLoop(self, pHead):

# write code here

slow,fast=pHead,pHead

while fast and fast.next:

slow=slow.next

fast=fast.next.next

if slow==fast:

slow2=pHead

while slow!=slow2:

slow=slow.next

slow2=slow2.next

return slow

發(fā)表于 2017-10-07 19:25:27

回復(fù)(14)

24

思路:leetcode上也有這道題,具體思想是,兩個指針fast和slow,fast以slow兩倍速度前進(jìn),

如果沒有環(huán),那么fast和slow不會相遇此時返回null;如果有環(huán),那fast和slow肯定會再次相遇

相遇的時候,fast剛好比slow多走了一圈環(huán)的長度。

用圖來描述下,當(dāng)fast與slow相遇時,fast走過的距離為a + b + c + b,而slow走過的距離為

a + b,因?yàn)閒ast是slow速度的兩倍,則有a+b+c+b = 2*(a+b),登出a=c;此時slow節(jié)點(diǎn)所處X處

到環(huán)起點(diǎn)Y處的距離a和X節(jié)點(diǎn)到Y(jié)處距離c其實(shí)是相等的,此時第三個指針p從x處,以和slow指針

相同的速度前進(jìn),當(dāng)它兩相遇時,即為環(huán)的起點(diǎn)Y處!

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) {

ListNode p = pHead;

while( p != slow) {

p = p.next;

slow = slow.next;

}

return p;

}

}

return null;

}

}

編輯于 2017-05-18 13:02:17

回復(fù)(9)

13

要尋找環(huán)的入口節(jié)點(diǎn),遍歷節(jié)點(diǎn)的時候,遇到的第一個重復(fù)節(jié)點(diǎn)肯定入環(huán)節(jié)點(diǎn),所以定義一個Set,

添加失敗時 即返回入口節(jié)點(diǎn)

import java.util.*;

public class Solution {

public ListNode EntryNodeOfLoop(ListNode pHead)

{

if(pHead==null)

return null;

ListNode pNode=pHead;

HashSet pSet = new HashSet();

while(pNode!=null){

if(!pSet.add(pNode))

return pNode;

pNode=pNode.next;

}

return null;

}

}

發(fā)表于 2016-06-18 10:34:08

回復(fù)(6)

8

class Solution:

def EntryNodeOfLoop(self, pHead):

# write code here

linkls = []

while pHead:

if pHead in linkls:

return pHead

linkls.append(pHead)

pHead = pHead.next

return None

發(fā)表于 2018-07-05 19:59:29

回復(fù)(13)

5

先貼代碼,再解釋; public ListNode EntryNodeOfLoop(ListNode pHead)

{

if (pHead == null || pHead.next == null)

return null;

//step1 發(fā)現(xiàn)環(huán)

ListNode walk = pHead, run = pHead;

do {

walk = walk.next;

run = run.next.next;

} while (walk != run);

//step2 找到了環(huán),并且run正在環(huán)內(nèi)

//另起一個quickWalk從pHead開始走,quickWalk和run再次相遇的地點(diǎn)就是環(huán)的入口

ListNode quickWalk = pHead;

while (quickWalk != run) {

run = run.next.next;

quickWalk = quickWalk.next.next;

}

return quickWalk;

}

}第一步發(fā)現(xiàn)環(huán),并找到了walk指針和run指針相遇的地點(diǎn)

第二步另起一個quickWalk指針,和run指針保持同步,倆指針相遇點(diǎn)即為入口;

解釋:

如圖,每個距離的含義: S:環(huán)入口到walk和run相遇點(diǎn)的距離

L:walk和run相遇點(diǎn)到入口的距離

P:頭結(jié)點(diǎn)到環(huán)入口的距離

設(shè)walk的速度是v,則run的速度是2v;

設(shè)相遇花費(fèi)了t時間,walk走過的路程為Swalk

根據(jù)題意有: 2vt - vt = vt,

又相遇的時候:vt = k(S+L)--①成立;

且 Swalk = vt = P + m(S+L) + S--②成立;

由①②可得 k(S+L) = P + m(S+L) + S

變形為:P = (k-m-1)(S+L) + L。

設(shè) q = (k-m-1),最終得到 P = q(S+L) + L。

因此分別從相遇地點(diǎn)、頭結(jié)點(diǎn)同時以相同的速度走的倆指針,最終相遇地點(diǎn)一定是環(huán)的入口。

PS:最后兩個同步指針的速度應(yīng)該是越快越好,因此,采用另起一個quickWalk指針和run同步,而不是和walk同步。

編輯于 2017-12-18 15:45:35

回復(fù)(1)

4

public class Solution {

public ListNode EntryNodeOfLoop(ListNode pHead) {

if(pHead == null || pHead.next == null) return null;

ListNode slow = pHead;

ListNode fast = pHead;

while (fast != null) {

fast = fast.next.next;

slow = slow.next;

if(fast == slow) break;

}

fast = pHead;

while (fast != slow) {

fast = fast.next;

slow = slow.next;

}

return slow;

}

}

發(fā)表于 2017-04-26 15:38:04

回復(fù)(0)

6

'''

解法:

第一步,先找到環(huán)中的一個節(jié)點(diǎn)(找到之后就可以計算出環(huán)中的節(jié)點(diǎn)數(shù)目)

讓一個指針fast走快一點(diǎn),一個指針slow走慢一點(diǎn);當(dāng)fast與slow相遇時,即fast比slow多一圈,此時相遇的節(jié)點(diǎn)肯定是環(huán)內(nèi)的節(jié)點(diǎn)

第二步,根據(jù)環(huán)中的節(jié)點(diǎn)來計算環(huán)中節(jié)點(diǎn)總數(shù)

從此節(jié)點(diǎn)遍歷到此節(jié)點(diǎn)結(jié)束,即可得到節(jié)點(diǎn)總數(shù)

第三步,知道了環(huán)內(nèi)節(jié)點(diǎn)總數(shù),來找到環(huán)入口

先讓一個指針p1從根節(jié)點(diǎn)開始往后走m步,然后再讓一個節(jié)點(diǎn)p2指向頭結(jié)點(diǎn);

然后讓p1和p2同時往后移動,當(dāng)p1與p2相交時,此時的點(diǎn)就是環(huán)的入口節(jié)點(diǎn)

'''

class Solution:

def EntryNodeOfLoop(self, pHead):

# write code here

meet_node = self.MeetNode(pHead)

if meet_node == None:

return None

# 得到環(huán)中的節(jié)點(diǎn)個數(shù)

loop_nodes = 1

p1 = meet_node

while p1.next != meet_node:

loop_nodes += 1

p1 = p1.next

# 目前已經(jīng)得到了環(huán)中節(jié)點(diǎn)個數(shù)m,和環(huán)中個一個節(jié)點(diǎn)meetnode,如何找到環(huán)的入口?

# 一個指針p1從根節(jié)點(diǎn)開始往后走m步,然后再讓一個節(jié)點(diǎn)p2指向頭結(jié)點(diǎn),p1和p2同時往后移動,當(dāng)p1與p2相交時,此時的點(diǎn)就是環(huán)的入口節(jié)點(diǎn)

p1 = pHead

for i in range(loop_nodes):

p1 = p1.next

p2 = pHead

while p1 != p2:

p1 = p1.next

p2 = p2.next

return p1

def MeetNode(self, pHead):

if pHead == None:

return None

slow = pHead.next

if slow == None:

return None

fast = slow.next

while slow != None and fast != None:

if slow == fast:

return slow

slow = slow.next

fast = fast.next

if slow != fast:

fast = fast.next

return None

編輯于 2018-05-19 14:52:05

回復(fù)(3)

6

//時間復(fù)雜度:O(n),用map對訪問過的節(jié)點(diǎn)做標(biāo)記,這樣如果訪問一個節(jié)點(diǎn)兩次,表明找到了環(huán)入口,否則沒有環(huán)。 表示map好好用啊~~

class EntryNodeOfLoop

{

public:

ListNode* EntryNodeOfLoop_Solution(ListNode* pHead)

{

if(pHead==nullptr) return nullptr;

ListNode *ptmp=pHead;

map mlist; //用map關(guān)聯(lián)各個鏈表指針和對應(yīng)的映射值

while(ptmp!=nullptr && mlist[ptmp]!=1)

{

mlist[ptmp]=1;//訪問過該鏈表節(jié)點(diǎn),就將實(shí)值改為1

ptmp=ptmp->next;

}

if(ptmp==nullptr) return nullptr; //沒有環(huán)

else return ptmp; //入口節(jié)點(diǎn)

}

};

發(fā)表于 2017-05-22 22:29:30

回復(fù)(3)

6

劍指offer 上面提到了一種很巧妙的方法:

1. 知道環(huán)的長度 len

2. 讓一個結(jié)點(diǎn)先走 len 然后讓另一個 和先走的那個一起走,兩者必然會相遇。

問題歸結(jié)為,計算len.

整體流程:

1. 用快慢指針求相遇的結(jié)點(diǎn)(如果不存在相遇的結(jié)點(diǎn),返回null 不用后面的計算)

2. ?求len

3. 求入口節(jié)點(diǎn)。

我們這里使用HashMap , 效率比 ArrayList 效率高點(diǎn)。

/*

public class ListNode {

int val;

ListNode next = null;

ListNode(int val) {

this.val = val;

}

}

*/

import java.util.HashMap;

public class Solution {

public ListNode EntryNodeOfLoop(ListNode pHead){

ListNode node = pHead;

HashMap map = new HashMap<>();

while(node!=null){

if(map.containsKey(node)){

return node;

}else{

map.put(node,true);

node = node.next;

}

}

return null;

}

}

發(fā)表于 2016-06-01 16:31:14

回復(fù)(3)

2

class?Solution:

def?EntryNodeOfLoop(self,?pHead):

a?=?[]

cur?=?pHead

while?cur:

if?cur?not?in?a:

a.append(cur)

cur?=?cur.next

else:

return?cur

return

發(fā)表于 2020-02-29 09:54:31

回復(fù)(0)

2

# 這樣把經(jīng)過的節(jié)點(diǎn)記錄下來就可以了呀 class Solution:

def EntryNodeOfLoop(self, pHead):

l = []

p = pHead

res = None

while p:

if p in l:

res = p

break

l.append(p)

p = p.next

return res

編輯于 2019-07-18 09:08:16

回復(fù)(1)

2

package entryNodeOfLoop;

import java.util.HashSet;

public class Solution {

public ListNode EntryNodeOfLoop(ListNode pHead) {

if (pHead == null) {

return null;

}

ListNode p = pHead;

HashSet set = new HashSet<>();

while (set.add(p)) {

if (p.next != null) {

p = p.next;

} else {

return null;

}

}

return p;

}

}

發(fā)表于 2018-03-10 21:29:48

回復(fù)(0)

2

//快慢指針。題目中明明說了有環(huán)。可是為何還要判斷下?

class Solution {

public:

ListNode* EntryNodeOfLoop(ListNode* pHead)

{

ListNode *slow = pHead;

ListNode *fast = pHead;

do{

if(fast == NULL || fast->next==NULL)

return NULL;

fast = fast->next->next;

slow = slow->next;

}while(slow != fast);

slow = pHead;

while(slow != fast){

slow = slow->next;

fast = fast->next;

}

return slow;

}

};

發(fā)表于 2017-06-07 14:48:40

回復(fù)(4)

總結(jié)

以上是生活随笔為你收集整理的链表中环的入口结点 python_链表中环的入口结点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。