赞
踩
目录
哈哈哈~~其实也就是带环的链表啦~~
或者是这样:
因此,环形链表有个特性,就是没有 tail,指针一旦进入环形部分,就是死循环,永远走不出来。
https://leetcode.cn/problems/linked-list-cycle/
首先,对链表的操作基本都是靠指针去完成的,因此肯定需要一个指针去维护这个链表,但环形链表有一个很重要的特性:就是由于有环状结构,因此指针一旦进入环状,就会在一直在链表里面,永远走不出来。因此我们应该用两个指针,一个遍历速度快一点,另一个遍历速度慢一点,简称“快慢指针”。
引用快慢指针之后,一旦慢指针进入环,通过快慢指针的速度差,当快指针追上慢指针的时候,就代表链表是环状的,否则快指针一旦为空,就说明链表不是环状链表。
注意:这里的快慢指针的相对速度必须是 1 !!!否则就可能出现移动次数除不尽的问题。就比如当相对速度是 2 ,但相对距离是奇数,那么移动次数就除不尽了,快指针就不会和慢指针相遇,而是直接超过慢指针。
- /**
- * Definition for singly-linked list.
- * struct ListNode {
- * int val;
- * struct ListNode *next;
- * };
- */
-
- bool hasCycle(struct ListNode *head)
- {
- /* 快慢指针 */
- if ((head == NULL) || (head->next == NULL))
- {
- return false;
- }
- else
- {
- struct ListNode *fast = head, *slow = head;
-
- while ((fast != NULL) && (fast->next != NULL))
- {
- fast = fast->next->next;
- slow = slow->next;
-
- if (fast == slow)
- {
- return true;
- }
- }
-
- return false;
- }
- }
https://leetcode.cn/problems/linked-list-cycle-ii/
简单来说就是如何找到图中的这个位置:
这里我们通过环形链表可以得出一些结论:
这里我们设起点到入口的距离是 L;入口到相遇点的距离为 X;链表的环型部分为 C;快指针速度为 2;慢指针速度为 1.
因此慢指针走的路程为:L + X。
到了这里,你或许就会问,为什么慢指针一定会在一圈内被快指针追上呢?
针对这个问题,我们可以这么想:假设最坏的情况(即快慢指针最远的相对距离)为在慢指针刚到入口时快指针在它的前面,那么距离为 C - 1。因为这两个指针的相对速度为1,因此总共要移动 (C - 1)/ 1 次,因此慢指针的移动距离为:1 *((C - 1)/ 1)< C。
言归正传,快指针走的路程为:n * C + X + L。
因此便有了如下等式:2(L + X)= n * C + X + L;
化简后就得出了如下结论:L = n * C - X
这个式子是什么意思呢?其实就是说在相同的时间内,慢指针从起点走到入口时,快指针从相遇点(X处)开始走 n 圈,最后与慢指针相遇,且此时新的相遇点恰好是环形链表的入口处!!!
- struct ListNode *detectCycle(struct ListNode *head)
- {
- struct ListNode *fast = head, *slow = head;
-
- while ((fast != NULL) && (fast->next != NULL))
- {
- /* 找相遇点 */
- fast = fast->next->next;
- slow = slow->next;
-
- if (fast == slow) /* 慢指针从起点出发,快指针从相遇点出发,速度都为1 */
- {
- slow = head;
-
- while (slow != fast)
- {
- slow = slow->next;
- fast = fast->next;
- }
-
- return slow;
- }
- }
- return NULL;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。