Linked List Cycle II的總結

Linked List Cycle II的總結

關鍵知識

鏈表的處理

解題思路

一種簡單的做法就是順序遍歷每個結點,然後每次都判斷該點是否在前面遍歷過的結點中,可以採用兩層遍歷的做法或者是採用set來存儲前面的結點,然後每次在set中find這個結點。但是set會將空間複雜度大大增加。
另一種做法就是採用快慢兩個指針在鏈表中遍歷,如果快慢指針會相遇,則說明鏈表中存在環,否則不存在。存在環後,再通過一定的數學方法找到起始結點。該做法的時間複雜度爲O(n),空間複雜度爲O(1),爲最佳做法。

簡單做法

首先初始化一個set,然後遍歷鏈表,不斷地比較該節點是否出現過,出現過則說明存在環,沒出現過就將此節點加進set,直到遍歷完整個鏈表。
時間複雜度: 平均爲O(n),最差爲O(n^2)
空間複雜度: O(n)

最佳解法

採用兩個指針分別爲fast和slow,fast指針遍歷的速度爲slow的兩倍,如果在fast到達鏈表結尾時兩個指針不相遇,則說明鏈表不存在環,如果存在環,由於兩者速度不一樣,必定相遇,且相遇也說明了鏈表存在環。相遇之後,用meet指針記錄相遇結點,然後用p指針指向起始結點head,然後兩個指針同步遍歷,直到兩者相遇的結點即爲環的起始結點。證明過程:
特殊例子
普遍證明

時間複雜度: O(n)
空間複雜度: O(1)

題目

Linked List Cycle II

簡答做法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        set<ListNode*> sl;
        ListNode* p = head;
        while (p) {
        	if (sl.find(p) == sl.end()) {
        		sl.insert(p);
        		p = p->next;
        	} else {
        		return p;
        	}
        }
        return nullptr;
    }
};

最優解法

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    	ListNode *fast = head, *slow = head, *meet = nullptr;
    	if (!head) return nullptr;
    	fast = head->next ? head->next->next : head->next;
    	slow = head->next;
    	while (fast) {
    		if (fast == slow) {
    			meet = slow;
    			break;
    		}
    		fast = fast->next ? fast->next->next : fast->next;
    		slow = slow->next;
    	}
    	if (!meet) return nullptr;
    	ListNode* p = head;
    	while (p != meet) {
    		meet = meet->next;
    		p = p->next;
    	}
    	return meet;
    }
};

題目地址

Linked List Cycle II

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章