Нахождение максимального произведения элемента массива и расстояния

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

Например, [2, 5, 2, 2, 1, 5, 2] -> 20, 5 и 5 (5 * (5-1)); [1, 2] -> 1

В первом примере максимальное произведение получится, если взять 5 и 5(a[1] и a[5]). Минимальный элемент пары — 5. Расстояние между элементами: 5 — 1 = 4. Результат: 5 * 4 = 20

Во втором примере имеется только одна пара. Минимальный элемент — 1. Расстояние между элементами — 1. Результат: 1*1 = 1.

не эффективное решение:

a = [2,5,2,2,1,5,2]
res = -10**9
for i in range(len(a)-1):
    for j in range(i+1,len(a)):
        res = max(res, min(a[i],a[j])*(j-i))

print(res)

Код работает медленно. Как я могу сделать его более эффективным?

Что значит «пройти сквозь время»?

Naveed Ahmed 30.08.2024 14:22

В первом примере максимальное произведение получится, если взять 5 и 5(a[1] и a[5]). Минимальный элемент пары — 5. Расстояние между элементами: 5 — 1 = 4. Результат: 5 * 4 = 20

Artem 30.08.2024 14:30

Во втором примере имеется только одна пара. Минимальный элемент — 1. Расстояние между элементами — 1. Результат: 1*1 = 1.

Artem 30.08.2024 14:32

Какие ограничения существуют на элементы a? Все ли они положительные? Строго положительный? Целые числа или числа с плавающей запятой?

lastchance 30.08.2024 15:13

@lastchance 0 >= a[i] >= 10 000

Artem 30.08.2024 15:22

@Artem Тогда массив должен быть пустым. Вы имеете в виду <= вместо >=? Кроме того, какова длина массива (минимальная и максимальная длина)?

no comment 30.08.2024 15:30

@nocomment 0 <= a[i] <= 10 000 (извините), 2 <= len(a) <= 100 000

Artem 30.08.2024 15:34

Значит, некоторые a[i] могут быть равны 0?

lastchance 30.08.2024 15:37

@lastchance Да

Artem 30.08.2024 15:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
9
82
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам определенно не нужно сравнивать все возможные пары, а лучше сосредоточиться на поиске максимального расстояния для каждого возможного минимального значения.

Вам больше нужно сосредоточиться на индексах, в которых возникает локальный минимум, вычислить расстояние между ними и другими элементами и пройти через массив, чтобы отслеживать самые дальние вхождения каждого элемента. Наконец, для каждого элемента вычислите произведение его значения и максимальное расстояние, которое он может создать с любым другим элементом (до или после него).

def maxProductOfMinAndDistance(a):
    n = len(a)
    left = [-1] * n
    right = [-1] * n
    
    # Initialize stack to maintain the indices of elements in the array
    stack = []
    
    # Fill left array
    for i in range(n):
        while stack and a[stack[-1]] >= a[i]:
            stack.pop()
        if stack:
            left[i] = stack[-1]
        stack.append(i)
    
    stack = []
    
    # Fill right array
    for i in range(n-1, -1, -1):
        while stack and a[stack[-1]] >= a[i]:
            stack.pop()
        if stack:
            right[i] = stack[-1]
        stack.append(i)
    
    # Compute the maximum product (third point)
    max_product = 0
    for i in range(n):
        if left[i] != -1:
            max_product = max(max_product, a[i] * (i - left[i]))
        if right[i] != -1:
            max_product = max(max_product, a[i] * (right[i] - i))
    
    return max_product


# Example 
a = [2, 5, 2, 2, 1, 5, 2]
print(maxProductOfMinAndDistance(a))  # Outputs 20

Необходимо отметить, что это O(n) линейно по временной сложности, так как левый и правый массивы вычисляются за время O(n), а окончательное вычисление максимального продукта также равно O(n).

Nijat Mursali 30.08.2024 14:34

Это дает неправильный результат при больших входных данных.

Artem 30.08.2024 14:36

Не могли бы вы предоставить примерные данные?

Nijat Mursali 30.08.2024 14:36

drive.google.com/file/d/1_WSe2WJ2ZioI12elg_J2vXWX_1ZfET2N/…

Artem 30.08.2024 14:39

Итерационный алгоритм дает другой ответ

Artem 30.08.2024 14:43

Каким должен быть результат для этих данных?

Nijat Mursali 30.08.2024 14:46

Итерационный алгоритм: 934833, Ваш алгоритм: 6848

Artem 30.08.2024 14:52

Это интересно, спасибо, что поделились. Я посмотрю на него и, если найду ответ, обновлю его.

Nijat Mursali 30.08.2024 14:54

@Artem Не могли бы вы сделать эти данные доступными без необходимости входа в систему всем, у кого есть ссылка?

no comment 30.08.2024 15:16

@nocomment disk.yandex.ru/d/LyatMBSzN5Aqzg Надеюсь, получится

Artem 30.08.2024 15:20

@nocomment dpaste.com/D2LZ8DR3N

Artem 30.08.2024 15:39

Вы можете попробовать это. Он имеет тот же номинальный порядок, но существенно уменьшает диапазон поиска, если a[i] мало.

Во внутренних циклах a[i] всегда является кандидатом на меньшее значение. Затем он ограничивает диапазоны поиска сверху и снизу.

Я сравнил ваше итеративное решение, а также ваш «большой» тестовый пример (который пришлось включать в код здесь немного долго).

import math

def iterative( a ):
    res = -10**9
    for i in range(len(a)-1):
        for j in range(i+1,len(a)):
            res = max(res, min(a[i],a[j])*(j-i))
    return res


def bestProduct( a ):
    best = 0
    lastIndex = len( a ) - 1
    for i in range( lastIndex ):
        if a[i] == 0: continue                                      # dratted edge case

        jup   = max( i + 1, math.ceil ( i + best / a[i] ) )         # reduce the search range ABOVE
        if jup <= lastIndex:
            jbest = i
            for j in range( jup, lastIndex + 1 ):
                if ( a[j] >= a[i] ): jbest = j                      # want the INDEX of the furthest that is >= a[i]
            if jbest != i: best = a[i] * ( jbest - i )

        jdown = min( i - 1, math.floor( i - best / a[i] ) )         # reduce the search range BELOW
        jbest = i
        if jdown >= 0:
            for j in range( jdown, -1, -1 ):
                if ( a[j] >= a[i] ): jbest = j
            if jbest != i: best = a[i] * ( i - jbest )

    return best


a = [2,5,2,2,1,5,2]
# a = [1,2]
# print( iterative( a ) )              # Uncomment to compare
print( bestProduct( a ) )

Вывод (простой случай):

20

Выход (большой случай):

934833

Не работает на [1, 2]

Artem 30.08.2024 16:02

Пришлось редактировать @Артем. Теперь это должно сработать. Мне нужно быть более осторожным с крайними случаями.

lastchance 30.08.2024 16:03

Все тесты пройдены

Artem 30.08.2024 16:24
Ответ принят как подходящий

О(n log n):

from itertools import accumulate
from bisect import bisect_left

a = [2,5,2,2,1,5,2]

print(max(
    x * (j - bisect_left(m, x))
    for a in [a, a[::-1]]
    for m in [list(accumulate(a, max))]
    for j, x in enumerate(a)
))

Попробуйте это онлайн!

Предположим, что лучшая пара имеет меньшее или равное значение в качестве правильного значения. Для каждого правого значения найдите самое дальнее левое значение, большее или равное (так, чтобы правое значение действительно было меньше или равное) и оцените эту пару. Проделайте все это как для данного массива, так и для него в обратном порядке, что охватывает случай, когда лучшая пара имеет меньшее или равное значение в качестве левого значения.

Вдохновлен вступительным абзацем Ниджата Мурсали.

Все тесты пройдены

Artem 30.08.2024 16:12

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

Эффективное интервальное хранение с использованием стандартной библиотеки C++
Самая длинная полная подпоследовательность упорядоченных гласных
Есть ли способ получить проекцию на заархивированные векторы std::tuple без лямбды?
Как оптимально разместить две точки на числовой прямой, чтобы минимизировать общее расстояние до набора заданных точек
Есть ли в этом алгоритме преобразования двоичного дерева поиска в отсортированный связанный список в Википедии ошибка?
Почему на этапе разделения быстрой сортировки используется одно условие остановки с двумя указателями L и R, а (L <= R)? Может ли это быть пока (L < R)?
Учитывая двоичную строку, подсчитайте количество плотных подстрок за время O (nlogn)
Диаметр двоичного дерева — неудачный случай, когда самый длинный путь не проходит через корень
Реализация Java, проблема производительности алгоритма Динича
Эффективный алгоритм сортировки 2d точек в набор границ Парето