Разбор задачи: K-я наименьшая простая дробь

Предложенный нами код:

 def kthSmallestPrimeFraction(self, arr, k):
        heap, used = [(arr[0] / arr[-1], 0, len(arr) - 1)], {(0, len(arr) - 1)}
        for i in range(k):
            try:
                cur, l, r = heapq.heappop(heap)
                used.add((l, r))
                if (l + 1, r) not in used:
                    heapq.heappush(heap, (arr[l + 1] / arr[r], l + 1, r))
                    used.add((l + 1, r))
                if (l, r - 1) not in used:
                    heapq.heappush(heap, (arr[l] / arr[r - 1], l, r - 1))
                    used.add((l, r - 1))
            except:
                break
        return [arr[l], arr[r]]

Вот подробный разбор решения задачи, по шагам, без упоминания сложности:

1. Инициализация

heap, used = [(arr[0] / arr[-1], 0, len(arr) - 1)], {(0, len(arr) - 1)}
  • Мы начинаем с того, что создаем кучу (heap), в которой храним кортежи вида (значение, индекс левого элемента, индекс правого элемента). Первоначально в куче находится один кортеж: это отношение первого элемента массива (arr[0]) к последнему элементу массива (arr[-1]), и индексы этих элементов (0 и последний индекс массива).
  • Также создаем множество used, чтобы отслеживать, какие индексы уже были обработаны и не попасть в цикл.

2. Основной цикл

for i in range(k):
    try:
        cur, l, r = heapq.heappop(heap)
        used.add((l, r))
  • Основной цикл выполняется k раз. В каждой итерации мы извлекаем наименьшее отношение из кучи. Метод heapq.heappop(heap) извлекает минимальный элемент из кучи и возвращает его как кортеж из трех элементов: значение отношения, индекс левого числа и индекс правого числа.
  • После этого добавляем пару индексов (l, r) в множество used, чтобы знать, что эта пара уже была рассмотрена.

3. Добавление новых элементов в кучу

if (l + 1, r) not in used:
    heapq.heappush(heap, (arr[l + 1] / arr[r], l + 1, r))
    used.add((l + 1, r))

if (l, r - 1) not in used:
    heapq.heappush(heap, (arr[l] / arr[r - 1], l, r - 1))
    used.add((l, r - 1))
  • Если пара (l+1, r) (сдвиг по левому индексу на 1) не была обработана, то мы добавляем ее в кучу. Это будет означать, что мы сдвигаем левую часть отношения вправо.
  • Точно так же, если пара (l, r-1) (сдвиг по правому индексу на 1) не была обработана, мы добавляем эту пару в кучу, сдвигая правую часть отношения влево.
  • Важно заметить, что добавляем новые индексы только в том случае, если они еще не были обработаны, благодаря проверке с множеством used.

4. Возврат результата

return [arr[l], arr[r]]
  • После выполнения k итераций, мы возвращаем пару чисел, которая соответствует индексу (l, r), на которых завершилось извлечение из кучи. Это будет пара чисел, образующих k-е наименьшее отношение в исходном массиве arr.

Пример

Вход: arr = [1, 2, 3, 5], k = 3

  • На первом шаге кучу будут содержать отношения: 1/5, 1/3, 2/5, а минимальное отношение — это 1/5.
  • После извлечения минимального отношения добавляется 1/3 и 1/2.
  • После извлечения еще одного отношения, добавляется 2/5, и на выходе получаем третий минимальный элемент 2/5.

Выход: [2, 5]

Таким образом, мы эффективно находим k-е минимальное отношение, правильно управляя кучей и отслеживая уже обработанные индексы.

 



Вы должны Войти или Зарегистрироваться чтобы оставлять комментарии