LeetCode演算法題-Linked List Cycle(Java實現)
這是悅樂書的第176次更新,第178篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第35題(順位題號是141)。給定一個連結串列,確定它是否有一個迴圈。
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 理解題意
什麼樣結構的連結串列才算是擁有一個迴圈呢?
連結串列中某一節點的引用指向了當前連結串列中已經存在的另一節點時,此連結串列存在迴圈。
ListNode L = new ListNode(1); ListNode L2 = new ListNode(2); ListNode L3 = new ListNode(3); ListNode L4 = new ListNode(4); ListNode L5 = new ListNode(5); ListNode L6 = new ListNode(6); L.next = L2; L2.next = L3; L3.next = L4; L4.next = L5; L5.next = L3;
上面的連結串列就存在迴圈,L5的引用指向了L3。如果僅僅是節點值相等,是不存在迴圈的,因為他們的引用始終不同。
03 第一種解法
可以打個比方,如果兩個人甲和乙同時在一條跑道上跑步,甲以2.5m/s的速度向前跑,乙以5m/s的速度向前跑,如果跑道是環形的,甲和乙肯定會在某一個地方至少相遇一次;如果跑道是直線形或非環形的,甲和乙是不會相遇的。
使用雙指標,一個是正常向前,一次移動一個節點,第二個是間隔一個節點向前移動,如果第二個指標碰到了可以迴圈的節點,會在迴圈的過程中遇到第一個指標,此時就滿足了形成迴圈的條件。
特殊情況:連結串列為空時,直接返回false。
public boolean hasCycle(ListNode head) { if (head == null) { return false; } ListNode slow = head; ListNode fast = head; while (slow != null && fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { return true; } } return false; }
04 第二種解法
還是以上面跑步為例,不過稍微有點變化。甲還是以2.5m/s的速度跑步,此時乙在跑道中給了甲一根棒子,並站在原地等甲把棒子還給自己,如果跑道是環形的,乙肯定是會等到甲把棒子還給自己,如果跑道是直線或者非環形的,甲就帶著棒子自己跑了。
我們可以使用一個標記,賦值給每一個節點,然後使用遞迴,直到碰到給出去的標誌為止。
public boolean hasCycle2(ListNode head) { if(head == null) { return false; } if (head.val == Integer.MIN_VALUE-1) { return true; } head.val = Integer.MIN_VALUE-1; return hasCycle2(head.next); }
如果某一個節點正好本身就擁有所要賦值的標誌呢?會有一定影響,如果限制節點值的取值範圍,此解法是完全可行的。
05 第三種解法
使用雜湊表,將每一個節點的引用都存起來,如果雜湊表中存在了某一個節點的引用,說明此連結串列是迴圈的。
public boolean hasCycle3(ListNode head) {
Set<ListNode> nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}
此解法的空間複雜度是O(n)。
06 小結
筆試或者面試遇到此題時,推薦第一種解法,如果有限制連結串列節點值的取值範圍,第二種解法也是完全可行的。
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!