Given a linked list, return
the node where the cycle begins. If there is no cycle, return null.
Do not modify the linked
list.
Can you solve it without
using extra space?
Задан связный список. Верните
указатель на вершину, в которой начинается цикл. Если цикла нет, верните null.
Не модифицируйте связный
список.
Решите задачу с константной
памятью.
// C++
/**
*
Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode
*detectCycle(ListNode *head)
{
}
};
// Java
/**
*
Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle (ListNode head) {
}
}
список
При помощи двух указателей
(медленного и быстрого) определим, содержит ли связный список цикл. Пусть
список содержит цикл, а p указывает
на вершину, в которой быстрый указатель догнал медленный. Установим q на начало списка.
Пусть расстояние от начала
до вершины, в которой начинается цикл, равно x. Расстояние от начала цикла до точки встречи двух указателей
равно y. Расстояние от вершины, на
которую указывает p, до начала цикла
по ходу списка равно z.
Предположим, что указатели
встретились так, что быстрый прошел только один круг цикла. То есть медленный
прошел путь x + y, а большой x + y + z
+ y. Учитывая, что быстрый указатель
вдвое быстрее медленного, получим равенство:
2 (x + y) = x + y
+ z + y или x = z
Это означает, что теперь
достаточно итеративно двигать указатели p
и q на один шаг пока они не
сравняются. Причем это обязательно случится в вершине, которая является началом
цикла.
Реализация алгоритма
class Solution
{
public:
ListNode *detectCycle(ListNode
*head)
{
if (!head) return
NULL;
ListNode* p = head;
ListNode* q = head;
while(q->next && q->next->next)
{
p = p->next;
q =
q->next->next;
if (p == q)
{
q = head;
while (p != q)
{
p =
p->next;
q =
q->next;
}
return p;
}
}
return NULL;
}
};
Java реализация
class Solution
{
public ListNode detectCycle(ListNode head)
{
if (head == null) return
null;
ListNode p = head;
ListNode q = head;
while(q.next != null && q.next.next != null)
{
p = p.next;
q = q.next.next;
if (p == q)
{
q = head;
while (p != q)
{
p = p.next;
q = q.next;
}
return p;
}
}
return null;
}
}