leetcode每日一道(8):神仙思路!對於一個給定的鏈表,求環的入口節點

1. 題目描述

對於一個給定的鏈表,返回環的入口節點,如果沒有環,返回null
拓展:
你能給出不利用額外空間的解法麼?

2. 一般思路

當然這個題如果見都沒見過的話,可能就很難了,鏈表我們一般只給定鏈表頭,然後節點的兩個屬性,一個是next,一個是val,那麼如何根據這兩個屬性,就知道鏈表環的入口節點呢,好像一個指針是沒有辦法的。

  • 判定有無環:快慢指針
    然後我們好像聽說過快慢指針的方法,快慢指針可以用來求鏈表的中點、等分點,也可以用來求鏈表的倒數節點,但是如何求入口節點呢,這個好像還要麻煩一點。
    想象一下,一個快指針一次兩步,一個慢指針一次一步,那麼如果有環的時候,這兩個指針怎麼樣?是不是肯定會遇上的?而且我們能確定的是,一定是在第一次快指針追上慢指針就遇上!爲什麼不能出現快指針直接越過慢指針的情況,這裏您可以去試一下,不會的。
  • 求環的長度:固定指針
    如何求出環的長度呢,既然快慢指針在有環的情況下能夠遇上,那麼當然是可以求出環的長度的。(一個指針動,另一個不動,跑一圈就行了)。
  • 求入口節點:先後指針
    有人說求出環的長度有啥用?可有用了,如果我們知道環的長度,那麼兩個指針從頭結點出發,一個指針先走環長度的步數,然後兩個指針一起走,遇上了之後不就是入口節點了嗎?

3. 神奇思路

在這裏插入圖片描述
這裏我更欣賞的是這樣的一種神奇的思路!先說明一下,X,Y分別代表表頭和入口節點,而Z代表着快慢指針的相遇位置!
不賣關子,先說結論:a=c。那試想,如果第一次相遇了,我們是不是隻需要把其中一個指針放到頭結點,然後兩個指針一起移動,下次相遇不就在入口節點了嗎??
證明也很簡單,我們假設快慢指針走了n步之後相遇在Z點,那麼快指針的路程是2n=a+b+c+b......(1)2n=a+b+c+b......(1)
慢指針的路程是n=a+b2n=a+b+a+b......(2)n=a+b,即2n=a+b+a+b......(2)
有意思的事情來了(怎麼這麼像朱一旦):(1)式和(2)式一等,不就得出了a=c的神仙結論了嗎?
接下來的事情就很簡單了。上代碼

4. 代碼

4.1 普通思路

class Solution {
public:
	ListNode *detectCycle(ListNode *head) {
		if (!head)
			return head;
		auto fast = head->next, slow = head;
		while (fast != slow) {
			if (!fast->next || !slow) {
				return nullptr;
			}
			fast = fast->next->next;
			slow = slow->next;
			
		}
		/*cout << fast->val << endl;
		cout << slow->val << endl;*/
		fast = fast->next;
		int circle = 1;
		while (fast != slow) {
			fast = fast->next;
			circle++;
			/*cout << fast->val << endl;
			cout << slow->val << endl;
			cout << circle << endl;*/
		}
		int i = 0;
		fast = head;
		slow = head;
		while (i<circle) {
			fast = fast->next;
			i++;
		}
		while (slow != fast) {
			slow = slow->next;
			fast = fast->next;
		}
		return slow;
	}
};

4.2 神仙思路

class Solution {
public:
	ListNode *detectCycle(ListNode *head) {
		if (!head)
			return head;
		auto fast = head, slow = head;
		while (fast && fast->next) {
			fast = fast->next->next;
			slow = slow->next;
            if(fast == slow)
                break;
			}
		if(!fast||!fast->next)
            return nullptr;
		slow = head;
		while (slow != fast) {
			slow = slow->next;
			fast = fast->next;
		}
		return slow;
	}
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章