Медиана двух отсортированных массивов — довольно известная проблема в литкоде. Реальная реализация решения 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(min(m,n))), зачем беспокоиться о O(log(m+n)) (что еще хуже)?
@RobbyCornelissen Исправлено значение O(log(m*n)), вопрос стал более конкретным. Почему return B[k - aStart];
нет return B[k-(aStart+bStart)];
Как уже упоминалось, цель алгоритма — найти медиану двух отсортированных массивов. Связанное решение достигает этого, выполняя Двоичный поиск, где ключевая идея состоит в том, чтобы рекурсивно сузить пространство поиска, отбрасывая примерно половину элементов из массивов на каждом этапе, тем самым достигая логарифмической временной сложности. Поскольку оба массива отсортированы, а 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.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 k представляет индекс медианного элемента в объединенных массивах. Корректировка k-aStart или k-bStart учитывает уже рассмотренные элементы из исчерпанного массива, гарантируя, что правильный элемент будет идентифицирован в оставшемся массиве. Таким образом, k не совсем равно aStart+bStart, а скорее скорректировано с учетом уже обработанных элементов.
Но это наивное решение работает, даже несмотря на то, что оно вычитает каждую половину обеих сторон. [Ссылка] return self.kth(a, b[ib + 1:], k - ib - 1)
и return self.kth(a[ia + 1:], b, k - ia - 1)
@user150497 user150497 Даже объединение обоих списков в более крупный список и их сортировка проходит через LeetCode, так что это мало о чем говорит.
@Unmitigated Вышеупомянутое наивное решение (код Python) в основном такое же (хотя нарезка не является постоянным временем). Не объединяя их в большой отсортированный список. Он удаляет половину обеих маленьких сторон. Но оказывается, что k == aStart + bStart.
На этом сайте нет алгоритма с временной сложностью
O(log(m+n))
. Тот, на который вы ссылаетесь, принадлежитO(log(m*n))
. Непонятно, о чем вы спрашиваете.