Reputation: 979
I have a list:
l = [1,3,4,6,7,8,9,11,13,...]
and a number n.
How do I efficiently check if the number n
can be expressed as the sum of two numbers (repeats are allowed) within the list l
.
If the number is in the list, it does not count unless it can be expressed as two numbers (e.g for l = [2,3,4] 3 would not count, but 4 would.
This, embarrassingly, is what I've tried:
def is_sum_of_2num_inlist(n, num_list):
num_list = filter(lambda x: x < n, num_list)
for num1 in num_list:
for num2 in num_list:
if num1+num2 == n:
return True
return False
Thanks
Upvotes: 4
Views: 2046
Reputation: 5302
If I got the OP's concern then-
As the question says repeats are allowed within the list l
this process i think is good though a bit slower.So if you need to count the occurances along with the existence of a condition then go with this answer but if you want a bolean esixtence check the go with the others for the mere performance issue nothing else.
You can use itertools.combinations. It will give you all the combinations, not permutations. Now you can just use the sum function to get the sum.
from itertools import combinations
l = [1,3,4,6,7,8,9,11,13]
checks = [4,6] #these are the numbers to check
for chk in checks:
for sm in combinations(l,2):
if chk == sum(sm): #sum(sm) means sum(1,3) for the first pass of the loop
#Do something
Upvotes: 0
Reputation:
If the list is ordered you could use two variables to go through the list, one starting at the beginning of the list and one at the end, if the sum of the two variables is greater than N you assign to the variable at the end the values that precedes it, if the sum is less than N you assign to the variable at the beginning the following value in the list. If the sum is N you've found the two values. You can stop when the two variables meet eachother.
If the list is not ordered you start from the beginning of the list and use a variable x
to go through the list. You'll need another structure like an hashset or another structure. At every step you'll look up in the second hashset if the value N-x
is in there. If there is, you've found the two numbers that add up to N. If there isn't you'll add N-x
in the hashset and assign to x
the following value. I recommend using an hashset because both the operations of looking up and inserting are O(1).
Both algorithms are linear
I'm sorry I couldn't write directly the code in python because I don't use it.
As I said in the comment HERE there's a video in wich your problem is solved
Upvotes: 1
Reputation: 50195
def summable(n, l):
for v in l:
l_no_v = l[:]
l_no_v.remove(v)
if n - v in l_no_v:
return True
return False
EDIT: Explanation...
The itertools.cominations
is a nice way to get all possible answers, but it's ~4x slower than this version since this is a single loop that bails out once it gets to a possible solution.
This loops over the values in l
, makes a copy of l
removing v
so that we don't add v
to itself (i.e. no false positive if n = 4; l = [2, 1]
). Then subtract v
from n
and if that value is in l
then there are two numbers that sum up to n
. If you want to return those numbers instead of returning True
just return n, n - v
.
Upvotes: 3
Reputation: 8254
Although you can check this by running through the list twice, I would recommend for performance converting the list to a set, since x in set()
searches in linear time.
Since n
can be the sum of the same number, all you have to do is iterate through the set once and check if n - i
occurs elsewhere in the set.
Something like the following should work.
>>> def is_sum_of_numbers(n, numbers):
... for i in numbers:
... if n - i in numbers:
... return True
... return False
...
>>>
>>>
>>> numbers = {2,7,8,9}
>>> is_sum_of_numbers(9, numbers) # 2 + 7
True
>>> is_sum_of_numbers(5, numbers)
False
>>> is_sum_of_numbers(18, numbers) # 9 + 9
True
Upvotes: 2