Разбор задачи: Цикл в связном списке

Предложенный нами код решения:

def has_cycle(head, pos):
    """
    Проверяет, существует ли цикл в связанном списке.
    
    :param head: Список чисел, представляющий элементы связанного списка.
    :param pos: Индекс, указывающий на элемент, к которому подключен хвост (если pos == -1, цикла нет).
    :return: True, если в списке есть цикл, иначе False.
    """
    # Если список пустой или состоит из одного элемента
    if not head or len(head) == 1:
        return False

    # Создаем словарь, чтобы отслеживать уже посещенные индексы
    visited = set()

    # Проходим по всем элементам списка
    current = 0
    while current != -1:  # Пока не дошли до конца списка (где current == -1)
        if current in visited:
            return True  # Если уже встречали этот индекс, значит есть цикл
        visited.add(current)  # Добавляем индекс в множество посещенных

        # Переходим к следующему элементу
        current = head[current] if current < len(head) else -1
        if current == -1 and pos != -1:
            # Если мы достигли конца списка и pos не -1, то создаем цикл
            current = pos
    
    return False

Задача заключается в том, чтобы определить, есть ли цикл в связанном списке. Связанный список представлен в виде массива чисел head, где каждое число указывает на следующий элемент, а значение -1 обозначает конец списка. Параметр pos указывает на индекс элемента, к которому подключен хвост списка, если цикл существует.

Алгоритм решения:

  1. Проверка на пустоту и одноэлементный список: Если список пустой (not head) или состоит из одного элемента (len(head) == 1), то очевидно, что в списке не может быть цикла. В таких случаях функция сразу возвращает False.
  2. Использование множества для отслеживания посещенных элементов: Для эффективной проверки наличия цикла используется множество (visited). Множество позволяет хранить уникальные элементы и быстро проверять, встречались ли они уже в процессе обхода списка. Если мы обнаружим, что текущий элемент уже находится в множестве, значит, мы обнаружили цикл.
  3. Обход списка: Начинаем с первого элемента списка (индекса 0). Пока не дойдем до конца списка (индекс -1), продолжаем двигаться по элементам.
    • Если текущий элемент уже встречался (он присутствует в множестве visited), значит, это цикличный список, и возвращаем True.
    • Если нет, добавляем текущий индекс в множество visited и переходим к следующему элементу, используя значение из списка head.
  4. Обработка хвоста с циклом: Если мы дошли до конца списка (индекс -1) и pos != -1, это значит, что в списке есть цикл, и мы должны перенаправить хвост на указанный элемент (индекс pos). В таком случае мы "замкнем" список, и процесс будет продолжаться до тех пор, пока не встретим повторяющийся элемент, указывающий на цикл.
  5. Возврат результата: Если мы обошли весь список и не нашли цикл, возвращаем False.

Пример 1:

Ввод:

head = [3, 2, 0, -4]
pos = 1

Разбор:

  1. Сначала мы проходим по индексу 0, который указывает на 3. Этот индекс добавляется в множество visited.
  2. Переходим по индексу 3, который указывает на -4. Этот индекс тоже добавляется в множество visited.
  3. Двигаемся к индексу -1 (конец списка), но так как pos = 1, то хвост списка теперь указывает обратно на 1-й элемент.
  4. Следовательно, после возвращения к индексу 1, мы видим, что он уже встречался, что указывает на наличие цикла.
  5. Возвращаем True.

Вывод:

True

Пример 2:

Ввод:

head = [1, 2]
pos = 0

Разбор:

  1. Мы начинаем с индекса 0, который указывает на 1. Этот индекс добавляется в множество visited.
  2. Переходим к индексу 1, который указывает на 2. Этот индекс также добавляется в множество visited.
  3. Двигаемся к индексу -1 (конец списка), но так как pos = 0, хвост списка снова указывает на 0.
  4. Возвращаемся к индексу 0, который уже встречался, что указывает на наличие цикла.
  5. Возвращаем True.

Вывод:

True

Пример 3:

Ввод:

head = [1]
pos = -1

Разбор:

  1. У нас есть только один элемент, который указывает на -1 (конец списка).
  2. Поскольку pos = -1, цикл не создается.
  3. В результате возвращаем False.

Вывод:

False

 



Вы должны Войти или Зарегистрироваться чтобы оставлять комментарии