Это вопрос домашнего задания. Они говорят, что принимает O(logN + logM)
где N
и M
являются длинами массивов.
Назовем массивы a
и b
. Очевидно, мы можем игнорировать все a[i]
и b[i]
где i> k.
Сначала сравним a[k/2]
и b[k/2]
. Пусть b[k/2]
> a[k/2]
. Поэтому мы можем отбросить и все b[i]
, где i> k / 2.
Теперь у нас есть все a[i]
, где i <k, и все b[i]
, где i <k / 2, чтобы найти ответ.
Каким будет следующий шаг?
arrays
algorithm
binary-search
Майкл
источник
источник
O(logN + logM)
виду только время, необходимое для поиска k-го элемента? Можно ли выполнить предварительную обработку объединения заранее?Ответы:
Вы получили это, просто продолжайте! И будьте осторожны с индексами ...
Чтобы немного упростить, я предполагаю, что N и M> k, поэтому сложность здесь O (log k), что составляет O (log N + log M).
Псевдокод:
Для демонстрации вы можете использовать инвариант цикла i + j = k, но я не буду выполнять всю вашу домашнюю работу :)
источник
Надеюсь, я не отвечаю на вашу домашнюю работу, так как этот вопрос был задан больше года назад. Вот хвостовое рекурсивное решение, которое займет время log (len (a) + len (b)).
Предположение: исходные данные верны. т.е. k находится в диапазоне [0, len (a) + len (b)]
Базовые случаи:
Шаги восстановления:
a
+ средний индексb
меньше чемk
a
больше, чем средний элементb
, мы можем игнорировать первую половинуb
, отрегулируйтеk
.a
, настройтеk
.k
меньше суммы средних индексовa
иb
:a
больше, чем средний элементb
, мы можем смело игнорировать вторую половинуa
b
Код:
Обратите внимание, что мое решение создает новые копии меньших массивов при каждом вызове, это можно легко устранить, передав только начальные и конечные индексы в исходных массивах.
источник
kthlargest()
он возвращает(k+1)
-й наименьший элемент, например,1
это второй наименьший элемент,0,1,2,3
т.е. ваша функция возвращаетsorted(a+b)[k]
.Многие люди ответили на вопрос «k-й наименьший элемент из двух отсортированных массивов», но обычно с помощью только общих идей, а не четкого рабочего кода или анализа граничных условий.
Здесь я хотел бы подробно рассказать о том, как я пошел, чтобы помочь некоторым новичкам понять, с моим правильным рабочим кодом Java.
A1
иA2
- два отсортированных по возрастанию массива с длинойsize1
иsize2
длиной соответственно. Нам нужно найти k-й наименьший элемент из объединения этих двух массивов. Здесь мы разумно предполагаем(k > 0 && k <= size1 + size2)
, что подразумевает этоA1
иA2
не может быть одновременно пустым.Во-первых, давайте подойдем к этому вопросу с помощью медленного алгоритма O (k). Метод заключается в сравнении первого элемента как массива, так
A1[0]
иA2[0]
. Меньшую возьмите, скажемA1[0]
, в карман. Потом сравнитеA1[1]
сA2[0]
и так далее. Повторяйте это действие, пока наш карман не достигнетk
элементов. Очень важно: на первом этапе мы можем взять на себя обязательства толькоA1[0]
в нашем кармане. Мы НЕ можем включать или исключатьA2[0]
!!!Следующий код O (k) дает вам один элемент перед правильным ответом. Здесь я использую его, чтобы показать свою идею и анализ граничных условий. После этого у меня правильный код:
Самая сильная идея заключается в том, что в каждом цикле мы всегда используем подход базового случая. После привязки к текущему наименьшему элементу мы приближаемся на один шаг к цели: k-му наименьшему элементу. Никогда не прыгайте в середину и не запутайтесь и не потеряйтесь!
Наблюдая выше код базового варианта
k == 1, k == size1+size2
, и в сочетании с , чтоA1
иA2
оба не могут быть пустыми. Мы можем превратить логику в более лаконичный стиль ниже.Вот медленный, но правильный рабочий код:
Теперь мы можем попробовать более быстрый алгоритм, работающий на O (log k). Точно так же сравните
A1[k/2]
сA2[k/2]
; еслиA1[k/2]
меньше, то все элементы отA1[0]
доA1[k/2]
должны быть у нас в кармане. Идея состоит в том, чтобы не просто фиксировать один элемент в каждом цикле; первый шаг содержитk/2
элементы. Опять же, мы НЕ можемA2[0]
вA2[k/2]
любом случае включать или исключать . Итак, на первом этапе мы не можем идти дальшеk/2
элементов. Для второго шага мы не можем идти дальшеk/4
элементов ...После каждого шага мы приближаемся к k-му элементу. В то же время каждый шаг становится все меньше и меньше, пока мы не дойдем до того
(step == 1)
, что есть(k-1 == index1+index2)
. Затем мы снова можем обратиться к простому и мощному базовому случаю.Вот рабочий правильный код:
Некоторые могут волноваться, а вдруг
(index1+index2)
перепрыгнет к-1? Можем ли мы пропустить базовый вариант(k-1 == index1+index2)
? Это невозможно. Вы можете сложить 0,5 + 0,25 + 0,125 ... и никогда не выйдете за пределы 1.Конечно, приведенный выше код очень легко превратить в рекурсивный алгоритм:
Надеюсь, что приведенный выше анализ и код Java помогут вам понять. Но никогда не копируйте мой код в качестве домашнего задания! Ура;)
источник
else if (A1[size1 - 1].compareTo(A2[size2 - 1]) < 0)
вместоelse if (A1[size1 - 1].compareTo(A2[size2 - 1]) > 0)
? (В коде kthSmallestSlowWithFault)Вот итеративная версия решения @lambdapilgrim на C ++ (см. Объяснение алгоритма там):
Он работает для всех
0 <= n < (size(a) + size(b))
индексов и имеетO(log(size(a)) + log(size(b)))
сложность.пример
источник
Моя попытка для первых k чисел, k-го числа в 2 отсортированных массивах и в n отсортированных массивах:
Полный код с утилитами отладки можно найти по адресу: https://github.com/brainclone/teasers/tree/master/kth
источник
Вот мой код, основанный на решении Жюля Оллеона:
источник
Вот моя реализация на C, вы можете обратиться к объяснениям алгоритма @Jules Olléon: идея алгоритма заключается в том, что мы поддерживаем i + j = k и находим такие i и j, чтобы a [i-1] <b [j-1] <a [i] (или наоборот). Теперь, поскольку в 'a' i элементов меньше, чем b [j-1], и j-1 элементов в 'b' меньше, чем b [j-1], b [j-1] является i + j-1 + 1 = k-й наименьший элемент. Чтобы найти такие i, j, алгоритм выполняет дихотомический поиск по массивам.
источник
Вот мое решение. Код C ++ печатает k-е наименьшее значение, а также количество итераций для получения k-го наименьшего значения с помощью цикла, который, на мой взгляд, находится в порядке log (k). Однако код требует, чтобы k было меньше, чем длина первого массива, что является ограничением.
источник
Первый псевдокод, представленный выше, не работает для многих значений. Например, вот два массива. int [] a = {1, 5, 6, 8, 9, 11, 15, 17, 19}; int [] b = {4, 7, 8, 13, 15, 18, 20, 24, 26};
В нем не работало при k = 3 и k = 9. У меня есть другое решение. Он приводится ниже.
Но ... он также не работает для k = 5. Есть четный / нечетный улов k, который не позволяет ему быть простым.
источник
источник
Вот мое решение на java. Постараюсь еще больше оптимизировать
Это вдохновлено Algo в замечательном видео на YouTube.
источник
Ссылка на сложность кода (log (n) + log (m))
Ссылка на код (log (n) * log (m))
Реализация решения (log (n) + log (m))
Я хотел бы добавить свое объяснение к проблеме. Это классическая проблема, когда мы должны использовать тот факт, что два массива отсортированы. нам даны два отсортированных массива arr1 размера sz1 и arr2 размера sz2
а) Предположим, если
Проверка правильности k
тогда мы не можем найти k-й наименьший элемент в объединении обоих отсортированных массивов ryt Итак, верните неверные данные. б) Теперь, если вышеупомянутое условие выполнено false и у нас есть действительное и допустимое значение k,
Управление крайними случаями
Мы добавим оба массива значениями -infinity спереди и значениями + infinity в конце, чтобы охватить крайние случаи k = 1,2 и k = (sz1 + sz2-1), (sz1 + sz2) и т. Д.
Основной алгоритм
Теперь мы выполним двоичный поиск по arr1. Мы выполним двоичный поиск по arr1 в поисках индекса i, startIndex <= i <= endIndex
такой, что если мы найдем соответствующий индекс j в arr2, используя ограничение {(i + j) = k}, то если
Поскольку мы знаем, что k-й наименьший элемент имеет (k-1) элементов меньше, чем он в объединении обоих массивов ryt? Так,
В случае 1 , что мы сделали, мы обеспечили наличие в общей сложности (k-1) меньших элементов для arr1 [i], потому что элементы меньше, чем arr1 [i] в массиве arr1, имеют количество i-1, чем мы знаем (arr2 [ j-1] <arr1 [i] <arr2 [j]), а количество элементов меньше arr1 [i] в arr2 равно j-1, поскольку j находится с использованием (i-1) + (j-1) = (k -1) Таким образом, k-й наименьший элемент будет arr1 [i]
Но ответ может не всегда поступать из первого массива, то есть arr1, поэтому мы проверили case2, который также удовлетворяет аналогично случаю 1, потому что (i-1) + (j-1) = (k-1). Теперь, если у нас есть (arr1 [i-1] <arr2 [j] <arr1 [i]), у нас есть всего k-1 элементов, меньших, чем arr2 [j] в объединении обоих массивов, так что это k-й наименьший элемент.
В случае 3 , чтобы преобразовать его в любой из случаев 1 или 2, нам нужно увеличить i, и j будет найдено в соответствии с использованием ограничения {(i + j) = k}, т.е. при двоичном поиске перейти в правую часть, т.е. сделать startIndex = middleIndex
В случае 4 , чтобы преобразовать его в любой из случаев 1 или 2, нам нужно уменьшить i, и j будет найден в соответствии с использованием ограничения {(i + j) = k}, т.е. при двоичном поиске перейти в левую часть, т.е. сделать endIndex = middleIndex .
Теперь, как определить startIndex и endIndex в начале двоичного поиска по arr1 с startindex = 1 и endIndex = ??. Нам нужно решить.
Поскольку, если k больше, чем размер первого массива, нам может потребоваться выполнить двоичный поиск по всему массиву arr1, иначе нам нужно взять только первые k его элементов, потому что элементы sz1-k никогда не могут участвовать в вычислении k-го наименьшего.
КОД показан ниже
Для решения сложности (log (n) * log (m))
Просто я упустил преимущество того факта, что для каждого i j можно найти с помощью ограничения {(i-1) + (j-1) = (k-1)} Таким образом, для каждого ii дополнительно применялся двоичный поиск по второму массиву найти j такое, что arr2 [j] <= arr1 [i]. Таким образом, это решение может быть дополнительно оптимизировано
источник
По сути, с помощью этого подхода вы можете отбрасывать k / 2 элементов на каждом шаге. K будет рекурсивно изменяться от k => k / 2 => k / 4 => ... до тех пор, пока не достигнет 1. Таким образом, сложность времени равна O (logk)
При k = 1 мы получаем самый низкий из двух массивов.
Следующий код находится на JAVA. Обратите внимание, что мы вычитаем 1 (-1) в коде из индексов, потому что индекс массива Java начинается с 0, а не с 1, например. k = 3 представлен элементом во 2-м индексе массива.
источник
Время Complexcity равно O (log (min (n, m)))
источник
Большинство ответов, которые я нашел здесь, касаются обоих массивов. Хотя это хорошо, но его сложнее реализовать, так как есть много крайних случаев, о которых нам нужно позаботиться. Кроме того, большинство реализаций являются рекурсивными, что увеличивает пространственную сложность стека рекурсии. Поэтому вместо того, чтобы сосредотачиваться на обоих массивах, я решил просто сосредоточиться на меньшем массиве и выполнить двоичный поиск только на меньшем массиве и настроить указатель для второго массива на основе значения указателя в первом массиве. В следующей реализации мы получаем сложность
O(log(min(n,m))
сO(1)
пространственной сложностью.У нас есть диапазон
[low, high]
для массива,a
и мы сужаем его по мере прохождения алгоритма.sizeA
показывает, сколько элементов изk
элементов находится в массиве,a
и является производным от значенияlow
иhigh
.sizeB
то же определение, за исключением того, что мы вычисляем значение таким образом, чтобыsizeA+sizeB=k
. На основе значений на этих двух границах делается вывод, что мы должны расширить до правой стороны в массивеa
или сжать до левой стороны. если мы застряли в той же позиции, это означает, что мы нашли решение и вернем максимальное количество значений в позицииsizeA-1
froma
иsizeB-1
fromb
.источник
Проверьте этот код.
источник
Ниже кода C # для поиска k-го наименьшего элемента в объединении двух отсортированных массивов. Сложность времени: O (logk)
источник
midA
изendA
еслиk < n
Проверить коротких массивов, начиная с.return B[startB + k - 1];
.)