Проблема со связанным списком - PullRequest
0 голосов
/ 18 сентября 2010

Хиии ...

Если нам даны два связанных списка (могут быть разной длины), так что несколько узлов с конца являются общими ... Как найти первый общий узел за наименьшее время ...?

Списки однозначно связаны. Некоторые узлы являются общими с конца, и нам нужно найти первый общий для обоих из них ОТ КОНЦА.

Ответы [ 3 ]

5 голосов
/ 18 сентября 2010
  • Подсчет обоих списков - O (n)
  • Пропустить разницу между длиной списков в длинном списке
  • Итерация одновременно по спискам, пока не будет найден общий узел - O (n)

Общая сложность: O (n)

Например:

1-> 2-> 3-> 4-> 7-> 8
--------- 5-> 6-> 7-> 8

Мы ожидаем получить 7 , так как это первый общий узел.

  1. Подсчет списков - первый = 6, второй = 4.
  2. Пропуск двух (6-4 = 2) элементов в первом (более длинном) списке.
  3. Итерация одновременно
    3.1. 3 == 5 неверно
    3.2. 4 == 6 неверно
    3.3. 7 == 7 верно, тогда 7 является общим узлом
1 голос
/ 18 сентября 2010

O (n) решение для поиска первого узла в одном из списков с тем же значением.Затем вы можете извлечь значение из этого узла.

Все разделы кода (комментарии) имеют значение O(1), если не указано иное, и вложенных операций O(n) нет.Следовательно, все решение - O (n).

. Оно работает путем подсчета элементов в каждом списке, а затем передвигает указатель для самого длинного списка, чтобы концы были выровнены.

Затем он проходит черезоба списка синхронизированы.Если узлы совпадают и ранее не сопоставлялись, он сохраняет этот узел (, а не , только если они совпадают, поскольку вы хотите, чтобы самое раннее совпадение в последовательности).

Если они не совпадают, вы сохраняете этот факт, так что последующее совпадение будет считаться самым ранним в последовательности.

К тому времени, как вы дойдете до конца обоих списков, у вас либо появится указание на то, чтоне было совпадения (если последний узел обоих списков различен) или самое раннее совпадение в последовательности.

Конечно, только псевдокод, поскольку это домашняя работа:

def findCommonNode (head1, head2):

    # Work out sizes O(n)

    set count1 and count2 to 0

    set ptr1 to head1
    while ptr1 is not equal to NULL:
        increment count1
        set ptr1 to ptr1->next

    set ptr2 to head2
    while ptr2 is not equal to NULL:
        increment count2
        set ptr2 to ptr2->next

    # If either size is 0, no match possible.

    if count1 == 0 or count2 = 0:
        return NULL

    # Make the first list longer (or same size).

    if count1 < count2:
        swap count1 and count2
        swap head1 and head2 (local copies only)

    # Move through longest list until they're aligned O(n).

    set ptr1 to head1
    set ptr2 to head2

    while count1 is greater than count2:
        decrement count1
        set ptr1 to ptr1->next

    # Initially mark as non-match.

    set retptr to NULL

    # Process both (aligned) lists O(n).

    while ptr1 is not equal to NULL:
        # If equal and if first match after non-match, save position.

        if ptr1->data is equal to  ptr2.data:
            if retptr is equal to NULL:
                set retptr to ptr1
        else:
            # If not equal, mark as non-match.

            set retptr to NULL

        # Advance to next element in both lists.

        set ptr1 to ptr1->next
        set ptr2 to ptr2->next

    # Return the earliest match.

    return retptr

Допустим,у вас есть два списка 1,2,3,4,5,5,6,7,8,9 и 0,6,9,8,9.Выровняв их и продвинув указатель списка 1 на основе разницы в размере, вы получите:

          v
1 2 3 4 5 5 6 7 8 9
          0 6 9 8 9
          ^

Затем установите соответствие NULL и начните обработку.Они не совпадают (5/0), поэтому вы устанавливаете первый соответствующий узел на NULL (даже если он уже равен NULL) и переходите к 6/6.

. Эти (6/6) совпадают (итекущее совпадение равно NULL), поэтому вы сохраняете адрес одного из них в качестве совпадения и продвигаетесь.

7/9 не совпадает, поэтому вы снова устанавливаете совпадение в NULL, а затем продвигаетесь.

8/8 совпадений, и совпадение равно NULL, поэтому вы снова устанавливаете совпадение для одного из них, затем переходите к следующему.

9/9 также соответствует , но совпадение уже установлено, поэтому выне меняй это.Затем продвиньтесь вперед и вы выйдете из элементов в обоих списках.

Затем вы вернете совпадение с одним из 8 узлов.И это самое раннее совпадение с общим трейлингом.

1 голос
/ 18 сентября 2010

Предполагая, что каждый связанный список имеет совершенно уникальный набор, единственный метод, который я вижу, состоит в том, чтобы использовать вложенный цикл for, который был бы ужасно неэффективным.Если наборы данных не уникальны, вы можете использовать третий (связанный) список в качестве кэша только уникальных узлов, но вы по-прежнему смотрите на худший случай O (n²)

...