Leetcode 141. 環(huán)形鏈表

給定一個鏈表,判斷鏈表中是否有環(huán)。

為了表示給定鏈表中的環(huán)喳篇,我們使用整數(shù) pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1态辛,則在該鏈表中沒有環(huán)麸澜。

示例 1:
輸入: head = [3,2,0,-4], pos = 1
輸出: true
解釋: 鏈表中有一個環(huán),其尾部連接到第二個節(jié)點奏黑。

示例 2:
輸入: head = [1,2], pos = 0
輸出: true
解釋: 鏈表中有一個環(huán)炊邦,其尾部連接到第一個節(jié)點。

示例 3:
輸入: head = [1], pos = -1
輸出: false
解釋: 鏈表中沒有環(huán)熟史。

進階:
你能用 O(1)(即馁害,常量)內(nèi)存解決此問題嗎?

題目分析:
這道題要求我們找出鏈表是否存在環(huán)蹂匹。我們先考慮當(dāng)鏈表無環(huán)時是怎樣的呢碘菜?如果一個鏈表無環(huán),那么當(dāng)我們從頭開始遍歷該鏈表到最后,每個點都只會被遍歷一次,并且結(jié)尾一定會存在一個空節(jié)點胡桨,標(biāo)記我們的鏈表遍歷結(jié)束。那么當(dāng)鏈表有環(huán)時计雌,當(dāng)我們遍歷該鏈表時,從鏈表中的某個點開始静尼,這個環(huán)中的點會被反復(fù)遍歷白粉。如示例1所示,從節(jié)點2開始鼠渺,2,0,4節(jié)點被反復(fù)遍歷鸭巴。既然有節(jié)點重復(fù),我們的直觀想法就是建立一個哈希表拦盹,該表中存儲節(jié)點的地址鹃祖,如果當(dāng)?shù)刂吩谠摴1碇写嬖跁r就表明有重復(fù)節(jié)點出現(xiàn),說明環(huán)存在普舆。否則算法遍歷到鏈表末尾空節(jié)點結(jié)束恬口。該算法只是遍歷鏈表所以時間復(fù)雜度為O(n)校读,n為鏈表的長度,因為我們額外建立了一張哈希表來存儲每一個節(jié)點的地址祖能,所以空間復(fù)雜度也是O(n)歉秫。

在面試中一開始如果你說出了一個這樣的初始解法,都會給面試官一個還算靠譜的印象养铸。但這道題作為一道簡單題雁芙,面試官聽了你的上述思路后并不會急于讓你實現(xiàn),而是會期望你給出一個空間復(fù)雜度為O(1)的解法钞螟,也就是本題的進階要求兔甘。

本題我們還是可以繼續(xù)使用鏈表題目中常見的快慢指針這一解題思路來進行解答。我們平時在繞著操場跑步時都有過這樣的體驗鳞滨,有的人跑的很快洞焙,而自己跑的很慢,那么跑的快的那個人就會在某個時刻趕上或者超過我們拯啦。那么這里也是同樣的澡匪,我們的慢指針每次只走一步,快指針每次走兩步褒链,如果鏈表沒有環(huán)仙蛉,快指針率先遍歷完鏈表到達鏈表末尾。如果鏈表有環(huán)碱蒙,那么在某個點快慢指針一定會相遇(即快慢指針有一樣的地址),相遇時我們就可以說鏈表中存在環(huán)了夯巷。這里我們只用了快慢指針的額外存儲空間赛惩,所以我們的空間復(fù)雜度就是O(1)
其實計算機科學(xué)家們已經(jīng)對此類環(huán)探測問題設(shè)計了相應(yīng)的理論和算法趁餐,我們上述的描述的形式化算法描述叫做Floyd Cycle Detection(佛洛依德環(huán)檢測算法)喷兼,有興趣的同學(xué)可以在網(wǎng)絡(luò)上搜索相應(yīng)資料深入了解一下。

有了上述的想法后雷,其實代碼寫出來就很直接了季惯,下面給出5種語言的實現(xiàn)。
c++實現(xiàn)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (head == NULL || head->next == NULL) return false;
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }
};

Go語言實現(xiàn)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func hasCycle(head *ListNode) bool {
    if head == nil || head.Next == nil {
        return false
    }

    var slow *ListNode = head
    var fast *ListNode = head
    for fast != nil && fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
        if slow == fast {
            return true
        }
    }

    return false
}

Java實現(xiàn)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }
}

C#實現(xiàn)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public bool HasCycle(ListNode head) {
        if (head == null || head.next == null) return false;
            var fast = head;
            var slow = head;
            while (fast != null && fast.next != null)
            {
                fast = fast.next.next;
                slow = slow.next;
                if (fast == slow)
                {
                    return true;
                }
            }
            return false;
    }
}

Python實現(xiàn)

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def hasCycle(self, head):
        if head == None or head.next == None:
            return False
        slow = head
        fast = head
        while fast != None and fast.next != None:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

最后也請大家想一下臀突,如果我們想把環(huán)的第一個節(jié)點找出來勉抓,我們還需要怎么設(shè)計我們的算法呢?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末候学,一起剝皮案震驚了整個濱河市藕筋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梳码,老刑警劉巖隐圾,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伍掀,死亡現(xiàn)場離奇詭異,居然都是意外死亡暇藏,警方通過查閱死者的電腦和手機蜜笤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盐碱,“玉大人把兔,你說我怎么就攤上這事〉楦鳎” “怎么了垛贤?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趣倾。 經(jīng)常有香客問我聘惦,道長,這世上最難降的妖魔是什么儒恋? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任善绎,我火速辦了婚禮,結(jié)果婚禮上诫尽,老公的妹妹穿的比我還像新娘禀酱。我一直安慰自己,他們只是感情好牧嫉,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布剂跟。 她就那樣靜靜地躺著,像睡著了一般酣藻。 火紅的嫁衣襯著肌膚如雪曹洽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天辽剧,我揣著相機與錄音送淆,去河邊找鬼。 笑死怕轿,一個胖子當(dāng)著我的面吹牛偷崩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播撞羽,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阐斜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诀紊?” 一聲冷哼從身側(cè)響起智听,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后到推,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體考赛,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年莉测,在試婚紗的時候發(fā)現(xiàn)自己被綠了颜骤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡捣卤,死狀恐怖忍抽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情董朝,我是刑警寧澤鸠项,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站子姜,受9級特大地震影響祟绊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哥捕,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一牧抽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遥赚,春花似錦扬舒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至愧薛,卻和暖如春衣赶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厚满。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碧磅,地道東北人碘箍。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像鲸郊,于是被迫代替她去往敵國和親丰榴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容