Я занимаюсь катами, чтобы улучшить свои навыки кодирования. Я сейчас в 6Kyu на Надеды . На этой неделе моя интересная проблема была:
Вам дают узел, который является началом связанного списка. Этот список всегда содержит хвост и петлю. Ваша цель – определить длину петли. Цикл выглядит так:
Как решить
Есть 2 части этого вопроса:
- Выяснить, когда вы находитесь в петле
- Считать узлы в петле
Фигура Когда ты в петле
После быстрого Google я обнаружил алгоритм обнаружения цикла Флойда, который, как говорится, обнаруживает, застряли ли вы в цикле. Вы также можете использовать его, чтобы найти именно то, где находится начало цикла, но это не связано с объемом этого вопроса.
Основная идея заключается в том, что у вас есть 2 указателя:
- Один перемещается к следующему узлу на 1 (медленный указатель)
- Второй указатель, который перемещается по 2 узлам (быстрый указатель)
Если список, в котором вы находитесь, действительно является петлей, оба должны встретиться в какой-то момент, так как оба будут ходить вокруг и раунд.
Поэтому код выглядит следующим образом:
function getNodeInLoop(node){
let slow = node;
let fast = node.next;
//problem assumes there is always going to be a loop
//so no need to check
while(slow !== fast){
slow = slow.next; //move by 1
fast = fast.next.next; //move by 2
}
return slow;
}
Поэтому мы возвращаем Известное место узла в петле.
Считать
Мы можем начать считать узлы! Мы принимаем наш узел, в котором как медленные, так и быстрые указатели соответствовали (здесь Seennode) как рассматривать его как корневой узел в цикле. Мы используем переменную «указателя», чтобы отслеживать там, что мы находимся в нашей петле и «счете», чтобы подсчитать количество узлов, через которые мы прошли:
let size = 1
let seenNode = getNodeInLoop(node);
let pointer = seenNode.next;
while(pointer !== seenNode ){
size++;
pointer = pointer.next;
}
return size;
Решение
Полное решение заключается в следующем:
function loop_size(node){
let size = 1;
let seenNode = getNodeInLoop(node);
let pointer = seenNode.next;
while(pointer !== seenNode ){
size++;
pointer = pointer.next;
}
return size;
}
function getNodeInLoop(node){
let slow = node;
let fast = node.next;
//problem assumes there is always going to be a loop
//so no need to check
while(slow !== fast){
slow = slow.next; //move by 1
fast = fast.next.next; //move by 2
}
return slow;
}
Та-да!
Ссылки
Вопрос о кодексах Алгоритм обнаружения цикла Флойда – явное объяснение на Hackerrank
P.S Я не уверен, почему, но Codewars не нравятся отдельные функции для решения, и, следовательно, большинство моих решений для кодирования просто написаны как одна функция. P.P.S Как всегда, это только мое решение, и я знаю, что есть другие реализации. Не стесняйтесь комментировать, чтобы начать обсуждение:)!
Оригинал: “https://dev.to/lost_semicolon/find-the-length-of-a-loop-in-a-linked-list-46i8”