Медиана алгоритма двух отсортированных массивов для O(log(m+n))

Медиана двух отсортированных массивов — довольно известная проблема в литкоде. Реальная реализация решения O(log(min(m,n))) довольно проста, но не O(log(m•n)). Основная идея — удалить маленькую половину и уменьшить Kth на количество удаленных элементов на каждом шаге. Как сказано

мы можем смело разрезать эту половину и уменьшить k на длину удаленной половины.

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

if (aEnd < aStart) {
    return B[k - aStart];
}
if (bEnd < bStart) {
    return A[k - bStart];
}

Начальный индекс как A, так и B может быть увеличен (то есть удален), но вычитается только один индекс: B[k - aStart] или A[k - bStart].

Как этот код имеет тот же эффект: «безопасно разрезать эту половину и уменьшать k на длину удаленной половины» на каждом шаге?

Код, if (aEnd < aStart) { return B[k - aStart]; } просто вычтите aStart из k. Я думаю, это должно быть что-то вроде B[k-(aStart+bStart)], чтобы также учитывались элементы, удаленные из B.

На этом сайте нет алгоритма с временной сложностью O(log(m+n)). Тот, на который вы ссылаетесь, принадлежит O(log(m*n)). Непонятно, о чем вы спрашиваете.

Robby Cornelissen 24.06.2024 10:31

Если у вас есть простой для понимания алгоритм O(log(min(m,n))), зачем беспокоиться о O(log(m+n)) (что еще хуже)?

MrSmith42 24.06.2024 11:36

@RobbyCornelissen Исправлено значение O(log(m*n)), вопрос стал более конкретным. Почему return B[k - aStart]; нет return B[k-(aStart+bStart)];

user150497 24.06.2024 12:00
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
2
3
103
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как уже упоминалось, цель алгоритма — найти медиану двух отсортированных массивов. Связанное решение достигает этого, выполняя Двоичный поиск, где ключевая идея состоит в том, чтобы рекурсивно сузить пространство поиска, отбрасывая примерно половину элементов из массивов на каждом этапе, тем самым достигая логарифмической временной сложности. Поскольку оба массива отсортированы, а k — это расширенный индекс того, где была бы медиана, если бы два массива были объединены, мы используем логику двоичного поиска, чтобы найти медиану без фактического объединения массивов.

Функция solve определена для выполнения двоичного поиска. Он принимает параметры k, aStart, aEnd, bStart и bEnd, которые представляют целевой индекс и текущие границы поиска в массивах A и B. Фрагмент, на который вы ссылаетесь,

if (aEnd < aStart) {
    return B[k - aStart];
}
if (bEnd < bStart) {
    return A[k - bStart];
}

Это базовый случай, обрабатывающий сценарий, когда сегмент одного массива исчерпан. Если мы исчерпаем сегмент массива A, мы фактически сведем задачу к поиску (k - aStart)-го элемента в массиве B, поскольку все значения в A были учтены.

  • k представляет k-ю позицию, которую мы ищем в объединенных отсортированных массивах.
  • Если все элементы от A до aStart учтены, эти элементы уже вносят вклад в k.
  • Новая k-я позиция относительно B должна учитывать количество уже рассмотренных элементов из A, следовательно, k - aStart.

Например, предположим, что у нас есть два отсортированных массива A и B:

A = [1, 3, 8, 15]
B = [7, 11, 18, 19, 21]

Мы пытаемся найти медиану объединенных отсортированных массивов. Объединенный массив будет:

[1, 3, 7, 8, 11, 15, 18, 19, 21]

Индекс медианы объединенного массива равен k = floor(9 / 2) = 4, что соответствует значению 11.

Алгоритм рекурсивно сужает пространство поиска. Вы можете самостоятельно отслеживать переменные по рекурсивным вызовам, но в конечном итоге сегмент A исчерпывается, aEnd < aStart, то есть все элементы в A были учтены. Когда выбран базовый случай, aStart = 3 и aEnd = 2. Поэтому, функция возвращает

B[k - aStart] = B[4 - 3] = B[1] = 11

что правильно.

Опять же, мы вычитаем aStart из k, так как это сужает позицию k, чтобы отразить оставшиеся элементы в B, учитывая количество элементов, уже учтенных в A. Эта настройка гарантирует, что даже когда один сегмент исчерпан, алгоритм по-прежнему правильно идентифицирует k-й элемент в другом массиве.

Эта логика применяется аналогичным образом, когда сегмент массива B исчерпан. Уменьшая k на aStart или bStart, мы корректно подстраиваемся под уже рассмотренные элементы и продолжаем поиск в оставшемся сегменте массива.

Возврат B[k - (aStart + bStart)] приведет к неправильному индексированию B. Помните, k — это индекс медианы в объединенных массивах. Когда один массив исчерпан, медиана лежит в другом, поэтому k следует корректировать только на количество рассматриваемых элементов из исчерпанного массива. Вычитание aStart + bStart из k приведет к неправильной индексации в неисчерпанном массиве.

Итак, когда один массив исчерпан, это значит, что k == aStart + bStart, не так ли?

user150497 25.06.2024 14:02

@user150497 k представляет индекс медианного элемента в объединенных массивах. Корректировка k-aStart или k-bStart учитывает уже рассмотренные элементы из исчерпанного массива, гарантируя, что правильный элемент будет идентифицирован в оставшемся массиве. Таким образом, k не совсем равно aStart+bStart, а скорее скорректировано с учетом уже обработанных элементов.

jjvraw 25.06.2024 14:40

Но это наивное решение работает, даже несмотря на то, что оно вычитает каждую половину обеих сторон. [Ссылка] return self.kth(a, b[ib + 1:], k - ib - 1) и return self.kth(a[ia + 1:], b, k - ia - 1)

user150497 25.06.2024 16:55

@user150497 user150497 Даже объединение обоих списков в более крупный список и их сортировка проходит через LeetCode, так что это мало о чем говорит.

Unmitigated 25.06.2024 18:41

@Unmitigated Вышеупомянутое наивное решение (код Python) в основном такое же (хотя нарезка не является постоянным временем). Не объединяя их в большой отсортированный список. Он удаляет половину обеих маленьких сторон. Но оказывается, что k == aStart + bStart.

user150497 26.06.2024 01:08

Другие вопросы по теме