leetcode每日一道(8):神仙思路!对于一个给定的链表,求环的入口节点

1. 题目描述

对于一个给定的链表,返回环的入口节点,如果没有环,返回null
拓展:
你能给出不利用额外空间的解法么?

2. 一般思路

当然这个题如果见都没见过的话,可能就很难了,链表我们一般只给定链表头,然后节点的两个属性,一个是next,一个是val,那么如何根据这两个属性,就知道链表环的入口节点呢,好像一个指针是没有办法的。

  • 判定有无环:快慢指针
    然后我们好像听说过快慢指针的方法,快慢指针可以用来求链表的中点、等分点,也可以用来求链表的倒数节点,但是如何求入口节点呢,这个好像还要麻烦一点。
    想象一下,一个快指针一次两步,一个慢指针一次一步,那么如果有环的时候,这两个指针怎么样?是不是肯定会遇上的?而且我们能确定的是,一定是在第一次快指针追上慢指针就遇上!为什么不能出现快指针直接越过慢指针的情况,这里您可以去试一下,不会的。
  • 求环的长度:固定指针
    如何求出环的长度呢,既然快慢指针在有环的情况下能够遇上,那么当然是可以求出环的长度的。(一个指针动,另一个不动,跑一圈就行了)。
  • 求入口节点:先后指针
    有人说求出环的长度有啥用?可有用了,如果我们知道环的长度,那么两个指针从头结点出发,一个指针先走环长度的步数,然后两个指针一起走,遇上了之后不就是入口节点了吗?

3. 神奇思路

在这里插入图片描述
这里我更欣赏的是这样的一种神奇的思路!先说明一下,X,Y分别代表表头和入口节点,而Z代表着快慢指针的相遇位置!
不卖关子,先说结论:a=c。那试想,如果第一次相遇了,我们是不是只需要把其中一个指针放到头结点,然后两个指针一起移动,下次相遇不就在入口节点了吗??
证明也很简单,我们假设快慢指针走了n步之后相遇在Z点,那么快指针的路程是 2 n = a + b + c + b . . . . . . ( 1 ) 2n=a+b+c+b......(1) 2n=a+b+c+b......(1)
慢指针的路程是 n = a + b , 即 2 n = a + b + a + b . . . . . . ( 2 ) n=a+b,即2n=a+b+a+b......(2) n=a+b2n=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;
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值