100題 第七題(單鏈表相交)

2021-08-26 12:54:25 字數 3618 閱讀 6014

題目:給出倆個單向鍊錶的頭指標,比如h1,h2,判斷這倆個鍊錶是否相交,

為了簡化問題,我們假設倆個鍊錶均不帶環。

問題擴充套件:

1,如果鍊錶可能有環列?

2,如果需要求出倆個鍊錶相交的第乙個節點列?

解答:

一,關於鍊錶有環的思考

理解: 1,

如何判斷鍊錶有環?

思考:單鏈表有環的判斷?什麼意思?一直向後遞迴遞迴到p->next=null;不就完了?

更正:如果一直向後遞迴,假如存在環的話,會出現死迴圈。

方法:【一】:可以做標記的話,在第乙個節點做上標記。若訪問到標記節點則有環,若訪問到null則無環。(這種方法不可取,只在所有節點構成乙個整環時才可以)

下圖:

【二】:不可以做標記的話,設定兩個節點slow,fast。slow每次走一步,fast每次走兩步。如果slow指標跟fast指標重合則表示有環。

【三】:應該還有方法待思考……

2,如何判斷環的長度

?記錄下問題1的碰撞點p,slow、fast從該點開始,再次碰撞所走過的運算元就是環的長度s。

3,如何找到環的入口在**?

有定理:碰撞點p到連線點的距離=頭指標到連線點的距離,因此,分別從碰撞點、頭指標開始走,相遇的那個點就是連線點。(證明在後面附註)

4,帶環鍊錶的長度是多少?

問題2求出環的長度,問題3求出頭指標到連線點的距離。兩者相加等於鍊錶長度。

程式原始碼:(待續)

void isloop(llink head)  //判斷是否存在環,如果有環則輸出(非環節點數,環節點數,總節點數)環開始節點

} if(!loop)

cout<

else

while(p!=r);

--loopcount;

while(p!=q)//得到環的入口結點,同時計算得到非環的結點數

--nonloop;

cout尋找環的入口的原始碼:

slist* findloopport(slist *head) //單純的找環開始點

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

return null;

slow = head;

while (slow != fast)

return slow;

}

尋找環入口方法二:亦可以用類似與hash表的方法,即設立乙個陣列,將鍊錶結點中的值做陣列下標,當賦值衝突時就是環的接入點

bool isloop(llink p)

return false;

}

建立乙個有環的鍊錶

llink creatlinkloop()

//建立乙個有環的鍊錶

cin.clear();

cin.sync();

srand(time(0));

q->next=findnode(head,rand()%n);//隨機產生環的接入點

return head;

}llink findnode(llink head,int n)//找出鍊錶中的第n個結點

二,分析與解法

a----b----c------d、 、

i-----j----null /

e-----f-----g------h

這樣的乙個問題,也許我們平時很少考慮。但在乙個大的系統中,如果出現兩個鍊錶相交的情況,而且釋放了其中乙個鍊錶的所有節點,那樣就會造成資訊的丟失,並且另乙個與之相交的鍊錶也會受到影響,這是我們不希望看到的。在特殊的情況下,的確需要出現相交的兩個鍊錶,我們希望在釋放乙個鍊錶之前知道是否有其他鍊錶跟當前這個鍊錶相交。

【解法一】直觀的想法

看到這個問題,我們的第乙個想法估計都是,「不管三七二十一」,先判斷第乙個鍊錶的每個節點是否在第二個鍊錶中。這種方法的時間複雜度為 o(length(h1) * length(h2))。可見,這種方法很耗時間。

【解法二】利用計數的方法(hash表 最簡單)

很容易想到,如果兩個鍊錶相交,那麼這兩個鍊錶就會有共同的節點。而節點位址又是節點的唯一標識。所以,如果我們能夠判斷兩個鍊錶中是否存在位址一致的節點,就可以知道這兩個鍊錶是否相交。乙個簡單的做法是對第乙個鍊錶的節點位址進行 hash 排序,建立hash 表,然後針對第二個鍊錶的每個節點的位址查詢 hash 表,如果它在 hash 表中出現,那麼說明第二個鍊錶和第乙個鍊錶有共同的節點。這個方法的時間複雜度為 o(max(length(h1)

+ length(h2)))。但是它同時需要附加 o(length(h1))的儲存空間,以儲存雜湊表。雖然這樣做減少了時間複雜度,但是是以增加儲存空間為代價的。是否還有更好的方法呢,既能夠以線性時間複雜度解決問題,又能減少儲存空間?

【解法三】鏈結「頭尾」判斷環法

由於兩個鍊錶都沒有環,我們可以把第二個鍊錶接在第乙個鍊錶後面,如果得到的鍊錶有環,則說明這兩個鍊錶相交。否則,這兩個鍊錶不相交這樣我們就把問題轉化為判斷乙個鍊錶是否有環。鍊錶有環的情況判斷乙個鍊錶是否有環,也不是乙個簡單的問題,但是需要注意的是,在這裡如果有環,則第二個鍊錶的表頭一定在環上,我們只需要從第二個鍊錶開始遍歷,看是否會回到起始點就可以判斷出來。最後,當然可別忘了恢復原來的狀態,去掉從第乙個鍊錶到第二個煉表表頭的指向。這個方法總的時間複雜度也是線性的,但只需要常數的空間。

【解法四】最後結點位址比較法

仔細觀察題目中的圖示,如果兩個沒有環的鍊錶相交於某一節點的話,那麼在這個節點之後的所有節點都是兩個鍊錶所共有的。那麼我們能否利用這個特點簡化我們的解法呢?困難在於我們並不知道哪個節點必定是兩個鍊錶共有的節點(如果它們相交的話)。進一步考慮「如果兩個沒有環的鍊錶相交於某一節點的話,那麼在這個節點之後的所有節點都是兩個鍊錶共有的」這個特點,我們可以知道,如果它們相交,則最後乙個節點一定是共有的。而我們很容易能得到鍊錶的最後乙個節點,所以這成了我們簡化解法的乙個主要突破口。

先遍歷第乙個鍊錶,記住最後乙個節點。然後遍歷第二個鍊錶,到最後乙個節點時和第乙個鍊錶的最後乙個節點做比較,如果相同,則相交,否則,不相交。這樣我們就得到了乙個時間複雜度,它為 o((length(h1) + length(h2)),而且只用了乙個額外的指標來儲存最後乙個節點。這個方法比解法三更勝一籌。

【如果兩個有環】判斷第乙個鏈,直鏈跟環交點為o1,判斷第二個鏈,直鏈跟環交點為o2。

比較o1跟o2位址,如果相等則相交,否則從o1遍歷,每次與o2位址比較,直到回到o1。期間有相等的則相交,否則不想交。

100題 第七題

題目 輸入乙個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。句子中單詞以空格符隔開。為簡單起見,標點符號和普通字母一樣處理。例如輸入 i am a student.則輸出 student.a am i 由於本題需要翻轉句子,我們先顛倒句子中的所有字元。這時,不但翻轉了句子中單詞的順序,而且...

VJ第七題題解

根據輸入的半徑值,計算球的體積。input 輸入資料有多組,每組佔一行,每行包括乙個實數,表示球的半徑。output 輸出對應的球的體積,對於每組輸入資料,輸出一行,計算結果保留三位小數。sample input 11.5 sample output 4.189 14.137 hint define...

程式設計素養第七題

jquery 中有哪些方法可以遍歷節點?children 取得匹配元素的子元素集合 next 取得匹配元素後面緊鄰的同輩元素 prev 取得匹配元素前面緊鄰的同輩元素 siblings 取得匹配元素前後的所有同輩元素 closest 取得最近的匹配元素 find 取得匹配元素中的元素集合,包括直接子...