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

#python #algorithm

#python #алгоритм

Вопрос:

Пусть A — непустое множество целых чисел. Напишите функцию find, которая выводит непустое подмножество A с максимальным произведением. Например, найти([-1, -2, -3, 0, 2]) = 12 = (-2)*(-3)*2

Вот что я думаю: разделите список на список положительных целых чисел и список отрицательных целых чисел:

  1. Если у нас есть четное число отрицательных целых чисел, умножьте все в обоих списках, и мы получим ответ.
  2. Если у нас нечетное число отрицательных целых чисел, найдите наибольшее и удалите его из списка. Затем умножьте все в обоих списках.
  3. Если список содержит только один элемент, верните этот элемент.

Вот мой код на Python:

 def find(xs):
    neg_int = []
    pos_int = []
    if len(xs) == 1:
        return str(xs[0])
    for i in xs:
        if i < 0:
            neg_int.append(i)
        elif i > 0:
            pos_int.append(i)
    if len(neg_int) == 1 and len(pos_int) == 0 and 0 in xs:
        return str(0)
    if len(neg_int) == len(pos_int) == 0:
        return str(0)
    max = 1
    if len(pos_int) > 0:
        for x in pos_int:
            max=x*max
    if len(neg_int) % 2 == 1:
        max_neg = neg_int[0]
        for j in neg_int:
            if j > max_neg:
                max_neg = j
        neg_int.remove(max_neg)
    for k in neg_int:
        max = k*max
    return str(max)
  

Я что-то пропустил? P.S. Это проблема из Google foobar challenge, я, по-видимому, пропустил один случай, но я не знаю, какой именно.

Теперь вот актуальная проблема: введите описание изображения здесь

Комментарии:

1. Я имел в виду численно наибольшее отрицательное значение, как -1> -3

2. Сделайте max_neg = abs(neg_int[0]) .. и выполняйте сравнения на основе абсолютного значения

3. Должен ли набор иметь минимальный размер? например [2, 3, 1, 1] , приводит к тому же продукту, [2, 3] что и . Говорит ли задача что-нибудь о том, как вы должны устранить это несоответствие?

4. Нет, это не так. Я должен сказать, что технически это не набор, поскольку могут существовать повторяющиеся значения.

5. @Lewis: думаю, я нашел ошибку в вашем коде: скажем, ввод: [-1] , ваш код возвращается 0 в качестве ответа.. Также в некоторых крайних случаях вы return 0 вместо return str(0)

Ответ №1:

 from functools import reduce
from operator import mul

def find(array):
    negative = []
    positive = []
    zero = None
    removed = None

    def string_product(iterable):
        return str(reduce(mul, iterable, 1))

    for number in array:
        if number < 0:
            negative.append(number)
        elif number > 0:
            positive.append(number)
        else:
            zero = str(number)

    if negative:
        if len(negative) % 2 == 0:
            return string_product(negative   positive)

        removed = max(negative)

        negative.remove(removed)

        if negative:
            return string_product(negative   positive)

    if positive:
        return string_product(positive)

    return zero or str(removed)
  

Ответ №2:

Вы можете упростить эту проблему с reduce помощью (in functools в Py3)

 import functools as ft
from operator import mul

def find(ns):
    if len(ns) == 1 or len(ns) == 2 and 0 in ns:
        return str(max(ns))
    pos = filter(lambda x: x > 0, ns)
    negs = sorted(filter(lambda x: x < 0, ns))
    return str(ft.reduce(mul, negs[:-1 if len(negs)%2 else None], 1) * ft.reduce(mul, pos, 1))

>>> find([-1, -2, -3, 0, 2])
'12'
>>> find([-3, 0])
'0'
>>> find([-1])
'-1'
>>> find([])
'1'
  

Комментарии:

1. Это решение, похоже, взрывается при вводе [-1] и не возвращает строки.

2. Хорошо, это не охватывало все особые случаи. Добавлена одна защита.

Ответ №3:

Вот решение в одном цикле:

 def max_product(A):
    """Calculate maximal product of elements of A"""
    product = 1
    greatest_negative = float("-inf") # greatest negative multiplicand so far

    for x in A:
        product = max(product, product*x, key=abs)
        if x <= -1:
            greatest_negative = max(x, greatest_negative)

    return max(product, product // greatest_negative)

assert max_product([2,3]) == 6
assert max_product([-2,-3]) == 6
assert max_product([-1, -2, -3, 0, 2]) == 12
assert max_product([]) == 1
assert max_product([-5]) == 1
  

Дополнительный кредит: что, если бы ограничение целого числа было ослаблено? Какую дополнительную информацию вам нужно собрать во время цикла?

Ответ №4:

Вот еще одно решение, которое не требует библиотек :

 def find(l):
    if len(l) <= 2 and 0 in l: # This is the missing case, try [-3,0], it should return 0
        return max(l)
    l = [e for e in l if e != 0] # remove 0s    
    r = 1
    for e in l: # multiply all
        r *= e 
    if r < 0: # if the result is negative, remove biggest negative number and retry
        l.remove(max([e for e in l if e < 0]))
        r = find(l)
    return r

print(find([-1, -2, -3, 0, 2])) # 12
print(find([-3, 0])) # 0
  

Редактировать :

Я думаю, что я нашел недостающий случай, когда в списке всего два элемента, а самый высокий равен 0.

Комментарии:

1. Это очень хорошее решение. Но он не проходит тот же тестовый пример, что и мой код. (К сожалению, я понятия не имею, в каком случае это так)

2. @Lewis моя мысль тоже, но на самом деле я не вижу, в каком случае это ни то, ни другое. Я буду продолжать искать, эта проблема забавная 🙂

3. На самом деле ваше решение терпит неудачу и в другом случае: find([0,-1)] выводит 1 вместо 0.

4. Я только что обновил вопрос. Пожалуйста, смотрите картинку в описании. 🙂

5. Когда вы даете этому коду одно отрицательное число, find([-3]) он возвращает 1 .