环链找起点(快慢指针)

环链找起点(快慢指针)

问题描述如下:

给定一个有环的链表,求开始进入环的那个结点,即下图的 target 。
环链找起点(快慢指针)

分析:

这个问题可以使用快慢指针来巧妙解决,快指针 fast 每次移动两个结点,

慢指针 slow 每次移动一个结点。

当 slow 和 fast 相遇的时候,slow —> target = head —> target = k

即慢指针和头结点到 target 的距离相同。
环链找起点(快慢指针)
这个时候 head 和 slow 一起往后移动,当它们相遇的时候,正好在 target

现在的问题是“当 slow 和 fast 相遇的时候,slow —> target = head —> target = k”这个结论是如何得到的。

设 fast 和 slow 相遇的时间为 t,slow 的速度为 1,fast 的速度为 2,

当 slow 和 fast 相遇的时候,fast 多走了一个环,设环的长度为 L 。
环链找起点(快慢指针)
即 2 * t - 1 * t = L => t = L

故 slow 走的路程 s = vt = 1*t = t = L

已知 head 到 target 的距离为 k,则 slow 逆向到达 target 的距离为 L-k
环链找起点(快慢指针)
而环的长度为 L,因此 slow 正向到达 target 的距离为 L - (L - k) = k

因此 slow —> target = head —> target = k 得证。

参考代码:

// 记录博客!求有环链表起点 快慢指针相遇时 他们与环起点的距离=head与环起点的距离 
#include<iostream>
using namespace std;

struct NODE {
	int data;
	NODE *next;
	NODE(){
		data = 0;
		next = NULL;
	}
	NODE(int n){
		data = n;
		next = NULL;
	}
};

// 很巧妙 快慢指针相遇的时候距离起点是k head距离起点也是k 
int getResult(NODE *head){
	NODE *fast = head->next, *slow = head->next;
	do{
		fast = fast->next->next;
		slow = slow->next;
	}while(fast != slow);
	NODE *p = head->next;
	while(p != slow){
		p = p->next;
		slow = slow->next;
	}
	return p->data;
}

int main(){
	int n;
	while(cin >> n){
		int begin;
		cin >> begin;
		NODE *head = new NODE();
		NODE *pre = head;
		NODE *p = head;
		for(int i = 0; i < n; i++){
			int in;
			cin >> in;
			p->next = new NODE(in);
			p = p->next;
			if(begin > 0){
				begin--;
				pre = p;
			}
		}
		p->next = pre;
		int ans = getResult(head);
		cout << ans << endl;
	} 
	return 0;
}

【END】感谢观看