2015-11-02 4 views
4

Вот моя проблема:Как проверить, соответствует ли сумма из 3 целых чисел в списке другому целому? (python)

У меня есть большое целое число (от 0 до 2^32-1). Назовем это число X. У меня также есть список целых чисел, в настоящее время несортированный. Все они являются уникальными числами, больше 0 и меньше X. Предположим, что в этом списке имеется большое количество предметов, скажем, более 100 000 предметов.

Мне нужно найти до 3-х цифр в этом списке (назовем их A, B и C), которые составляют до X. A, B и C все должны быть внутри списка, и они могут быть повторяется (например, если X равно 4, я могу иметь A = 1, B = 1 и C = 2, хотя 1 будет отображаться только один раз в списке).

Может быть несколько решений для A, B и C, но мне просто нужно найти одно возможное решение для каждого из самых быстрых способов.

Я попытался создать для структуры петли, как это:

For A in itemlist: 
    For B in itemlist: 
    For C in itemlist: 
     if A + B + C == X: 
     exit("Done") 

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

Есть ли способ найти решение для A, B и C без использования безумного объема памяти или принятия безумного времени? Заранее спасибо.

+0

Используйте ['itertools.combinations'] (https://docs.python.org/2/library/itertools.html#itertools.combinations) – inspectorG4dget

+0

вы можете использовать' while index1

+0

Вы можете попробовать сначала отсортировать списки и «перебить» ток для вложенного цикла, если «A + B> X» (во втором 'for') или' A + B + C> X' (в третьем). Поступая таким образом, вы можете сэкономить некоторые вычисления, это похоже на обратный алгоритм. Тем не менее, я не уверен, что он действительно будет работать лучше. – Delgan

ответ

3

вы можете уменьшить время работы от п^3 п^2, используя набор что-то вроде этого

s = set(itemlist) 
for A in itemlist: 
    for B in itemlist: 
     if X-(A+B) in s: 
      print A,B,X-(A+B) 
      break 

Вы также можете отсортировать список и использовать бинарный поиск, если вы хотите, чтобы сохранить память

+0

Я не уверен, что это O (n^2). Тестирование «in» в постановке для включения включения внутри цикла doulble не является постоянным временем. Возможно, это O ((n^2) logn). – RobertB

+0

набор реализован с использованием хеш-таблицы, которая обеспечивает O (1) время поиска в операторе здесь, используя хеш-таблицу – m7mdbadawy

+0

@RobertB Я думаю, что 'in' for' set' равно O (1), потому что доступ к значениям амортизируется благодаря значениям хэша , Вот почему этот ответ очень умный. – Delgan

1
import itertools 

nums = collections.Counter(itemlist) 
target = t # the target sum 
for i in range(len(itemlist)): 
    if itemlist[i] > target: continue 
    for j in range(i+1, len(itemlist)): 
     if itemlist[i]+itemlist[j] > target: continue 
     if target - (itemlist[i]+itemlist[j]) in nums - collections.Counter([itemlist[i], itemlist[j]]): 
      print("Found", itemlist[i], itemlist[j], target - (itemlist[i]+itemlist[j])) 
+0

'k' не определено –

+0

@BrentWashburne: спасибо, что указали это. Исправлена! – inspectorG4dget

0

Заимствуя @ inspectorG4dget КОДЕКС, это имеет две модификации:

  1. Если C < B то мы можем шор t-контур петли.
  2. Использовать bisect_left() вместо collections.Counter().

Это, кажется, работает быстрее.

from random import randint 
from bisect import bisect_left 

X = randint(0, 2**32 - 1) 
itemset = set(randint(0,X) for _ in range(100000)) 
itemlist = sorted(list(itemset)) # sort the list for binary search 
l = len(itemlist) 

for i,A in enumerate(itemlist): 
    for j in range(i+1, l):   # use numbers above A 
     B = itemlist[j] 
     C = X - A - B    # calculate C 
     if C <= B: continue  
     # see https://docs.python.org/2/library/bisect.html#searching-sorted-lists 
     i = bisect_left(itemlist, C) 
     if i != l and itemlist[i] == C: 
      print("Found", A, B, C) 

Чтобы уменьшить число сравнений, мы проводим A < B < C.

+0

Вы правы. Обновите код соответствующим образом. –

Смежные вопросы