Автор оригинала: Shubham Sayon.
🏢 Это один из Google Вопросы собеседования и сообщают программистами по всему миру как один из общего задания вопросов во время интервью. Итак, вы можете дать оптимальное решение этой проблемы?
Постановка проблемы
Дано целочисленный массив или Python Список Nums
целочисленное значение x
и к
Отказ
Найти и вернуть к
Наиболее близкие цифры на вход X в массиве.
⚠️ Ограничения : Вы можете предположить, что к
это число между 1
и длина Nums
список.
1 длиной
- Поэтому неявно гарантировано, что список
Nums
Имеет хотя бы один элемент, и всегда должен быть точно одним решением.
- Поэтому неявно гарантировано, что список
Nums
отсортирован в порядке возрастания.
💡examples.
Давайте посмотрим на некоторые примеры для улучшения нашего понимания этой проблемы.
Example 1 Input: [8, 10, 12, 15, 18, 20], k = 4, x = 15 Output: [10, 12, 15, 18] Example 2 Input: [4, 6, 8, 9], k = 3, x = 7 Output: [6, 8, 9] Example 3 Input: [2, 3, 5, 6, 7], k = 1, x = 4 Output: [3] Example 4 Input: [5], k = 1, x = 4 Output: [5] Example 5 Input: [10, 11, 12, 13, 15, 16], k = 1, x = 15 Output: [15]
🖊️an Легкий подход: двоичный поиск
Самым простым решением этой проблемы является использование Бинарный поиск следующее:
- Сначала используйте алгоритм двоичного поиска, чтобы найти точку вставки (точка вставки – точка, в которой целое число
х
Может быть размещен или вставлен в отсортированный список). Элементы до этого момента меньше, в то время как элементы после его больше. - Затем сравните элементы вокруг этой точки, чтобы найти
к
ближайшие номера.
Давайте посмотрим на код, который выполняет это:
def binary(nums, x): start = 0 end = len(nums) - 1 while start <= end: mid = start + ((end - start) // 2) if nums[mid] < x: start = mid + 1 elif nums[mid] > x: end = mid - 1 else: return mid return start def k_close(nums, x, k): no = binary(nums, x) lhs = no - 1 rhs = no while k > 0: if lhs < 0 or (rhs < len(nums) and abs(nums[lhs] - x) > abs(nums[rhs] - x)): rhs = rhs + 1 else: lhs = lhs - 1 k = k - 1 return nums[lhs + 1: rhs]
Давайте запустим этот код на наших примерах:
# Example 1 nums = [8, 10, 12, 15, 18, 20] k = 4 x = 15 print(k_close(nums, x, k)) # [10, 12, 15, 18] # Example 2 nums = [4, 6, 8, 9] k = 3 x = 7 print(k_close(nums, x, k)) # [6, 8, 9] # Example 3 nums = [2, 3, 5, 6, 7] k = 1 x = 4 print(k_close(nums, x, k)) # [3] # Example 4 nums = [5] k = 1 x = 5 print(k_close(nums, x, k)) # [5] # Example 5 nums = [10, 11, 12, 13, 15, 16] k = 1 x = 15 print(k_close(nums, x, k)) # [15]
Ура! 😃 Код передал все тестовые случаи.
❖ Анализ: Код состоит из двух функций: двоичный поиск и поиск ближайшего числа k. Двоичный поиск алгоритм имеет временную сложность O (log (n)) . Сложность времени для поиска ближайших чисел K – Ok) . Следовательно, общая сложность этого кода становится O (журнал n + k) Отказ
💡 Тидбит: Двойная ярмарка //
Оператор выполняет Целочисленное разделение и одноотечка /
Оператор выполняет поплавок подразделение. Пример для целочисленного подразделения – 40//11
Отказ Пример для поплавкового разделения – 40/11.6363636363636362
Отказ
❖ Обсуждение: Мы провели много дополнительной работы в приведенном выше подходе, поскольку мы выполняем двоичный поиск всего списка внутри одного метода, а затем мы использовали другой метод для вычисления к
ближайшие числа к данному значению x
. Есть ли лучший способ справиться с этой проблемой?
🖊 ️ Оптимальное решение
Лучший способ сочетать как методы, так и генерировать оптимальное решение. Основная идея этого алгоритма – узнать нижнюю оценку для данного к
Диапазон длины. Числа между « покинули
» и « правый
» – это кандидаты нижней границы.
❖ Подход: Предполагая, что [MID] ~ A [MID + K] представляет раздвижное окно, мы сравниваем расстояние между х - а [середина]
и [MID + K] - X
Отказ Теперь давайте рассмотрим следующие случаи:
- до тех пор, пока
X - [MID]> [MID + K] - X
Нам нужно переместить окно иди справа. - В противном случае нам нужно переместить окно слева.
Вот пример, который иллюстрирует алгоритм:
Теперь давайте посмотрим на код:
def k_close(nums, x, k): left, right = 0, len(nums) - k while left < right: mid = (left + right) // 2 if x - nums[mid] > nums[mid + k] - x: left = mid + 1 else: right = mid return nums[left:left + k]
❖ Обсуждение:
- Если состояние
X - [MID]> [MID + K] - X
используется для сравнения[Середина] и [середина + к]
Чтобы проверить, что ближе кх
Отказ - Если
[Середина]
ближе кх
Тогда[MID + K]
никогда не может быть вк
Диапазон длины. Таким образом, вы определенно можете удалить все ([MID + 1], [MID + 2], [MID + 3] … ) из списка кандидатов, установивсправа = середина
. - Если
[MID + K]
ближе кх
Тогда[Середина]
никогда не может быть вк
Диапазон длины. Таким образом, вы можете удалить все ( …a [MID-2], [MID-1], [MID] ) из списка кандидатов, установивслева = середина + 1
Отказ - Как только вы остались только с одним кандидатом, то есть
слева == право
, вы получили нашу последнюю нижнюю границу, и теперь вы можете вернутьк
Ближайшие номера, нарезающие список.
❖ Тестовые случаи:
00с | k | x | Выход |
[8, 10, 12, 15, 18, 20] | 4 | 15 | [10, 12, 15, 18] |
[4, 6, 8, 9] | 3 | 7 | [6, 8, 9] |
[2, 3, 5, 6, 7] | 1 | 4 | [3] |
[5] | 1 | 5 | [5] |
[10, 11, 12, 13, 15, 16] | 1 | 15 | [15] |
❖ Анализ сложности времени:
Операции по переносу указателей и вычисляют ближайшие числа в цикле, имеют временную сложность O (log (n-k)) и временная сложность для кусочек Список и возврат желаемого вывода – Ok). Таким образом, общая сложность этого алгоритма этого алгоритма является O (log (n-k) + k) Отказ
Давайте рассмотрим следующий пример, чтобы проанализировать временную сложность:
Дано :
nums = [10, 11, 12, 13, 15, 16, 18, 19, 20, 22, 23] k = 3 x = 15
Давайте предположим, что длина номеров its ‘n’. Таким образом, мы сокращаем указатели/окна (N-K) Шаги, как показано в таблице ниже. Таким образом, Хотя петля имеет сложность O (log (n – k)) Отказ
- В приведенном выше примере и Отказ Таким образом, пока цикла проходит Журнал (N-K) итерации, то есть Журнал (11-3) ⇒ Журнал 8 = 3 итерации Отказ
- Наконец, когда мы возвращаем нарезанный список, который представляет собой окно, содержащее К ближайшим Соседи, это берет O (k) время.
- Следовательно, общая сложность становится O (log (n – k) + k) Отказ
🖊️a Бонусное решение: Использование бисекта и двух указателей
Прежде чем обсуждать этот подход, вам нужно понять, что bisect.bisect_left
делает. В кодирующем интервью вы обычно можете предположить, что у вас есть доступ к базовым внешним функциям. Вот базовый рециллер по идее метода бисекта:
📗 Bisect Recap : ◆ Цель Биссект Алгоритмы – найти Индекс/должность требуемого элемента в данном списке, где элемент должен быть вставлен в список. Поэтому он помогает сохранить список отсортирован после завершения вставки. ◆ bisect_left
Метод биссект
Модуль используется для поиска индекса целевого элемента в отсортированном списке. Если элемент уже присутствует в списке, то левое место, где элемент может быть вставлен в список, возвращается.
❖ Подход : Основная идея этого решения – найти Точка вставки по стоимости х
Используя bisect.bisect_left
Функция в модуле. Затем мы будем использовать два указателя, чтобы найти к
ближайшие элементы.
Давайте посмотрим на код:
import bisect def k_close(nums, x, k): pos = bisect.bisect_left(nums, x) left, right = pos - 1, pos while k: if right >= len(nums) or \ (left >= 0 and abs(nums[left] - x) <= abs(nums[right] - x)): left -= 1 else: right += 1 k -= 1 return nums[left + 1:right]
❖ Анализ времени выполнения: Функция Bisect работает неоднократно сокращенным списком. Это означает, что он имеет время работы O (log n) Отказ Алгоритм берет O (k) Время для поиска к
ближайшие номера. Следовательно, общая сложность для этого решения является O (журнал n + k) Отказ
Примечание : Это фантастический подход, который можно было придумать во время интервью. Однако следует отметить, что интервьюеры могут на самом деле попросить вас реализовать алгоритм, который использует двоичный поиск.
Заключение
Я надеюсь, что вам понравилось этот опрос кодирования. Пожалуйста, оставайся настроенными и Подписаться Для более интересных проблем кодирования.
Почтовые кредиты: Шубхам Сайон и Раши Агарваль
Рекомендуется: Академия компьютерной науки Finxter
- Вы хотите быстро освоить самые популярные Python IDE?
- Этот курс приведет вас от новичка к эксперту в Пычарме в ~ 90 минут.
- Для любого разработчика программного обеспечения имеет решающее значение для освоения IDE хорошо, писать, тестировать и отлаживать высококачественный код с небольшим усилием.
Присоединяйтесь к Pycharm MasterClass Сейчас и мастер Pycharm на завтра!
Я профессиональный Python Blogger и Content Creator. Я опубликовал многочисленные статьи и создал курсы в течение определенного периода времени. В настоящее время я работаю полный рабочий день, и у меня есть опыт в областях, таких как Python, AWS, DevOps и Networking.
Вы можете связаться со мной @:
Оригинал: “https://blog.finxter.com/k-closest-numbers-in-sorted-array/”