Leetcode Two Sum code in Python
$begingroup$
Here's my solution for the Leet Code's Two Sum problem -- would love feedback on (1) code efficiency and (2) style/formatting.
Problem:
Given an array of integers, return indices of the two numbers such
that they add up to a specific target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
My solution:
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
for num_other in num_lst[indx+1:]:
if nums[num] + nums[num_other] == target:
return [num, num_other]
else:
continue
return None
python python-3.x k-sum
$endgroup$
add a comment |
$begingroup$
Here's my solution for the Leet Code's Two Sum problem -- would love feedback on (1) code efficiency and (2) style/formatting.
Problem:
Given an array of integers, return indices of the two numbers such
that they add up to a specific target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
My solution:
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
for num_other in num_lst[indx+1:]:
if nums[num] + nums[num_other] == target:
return [num, num_other]
else:
continue
return None
python python-3.x k-sum
$endgroup$
2
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06
add a comment |
$begingroup$
Here's my solution for the Leet Code's Two Sum problem -- would love feedback on (1) code efficiency and (2) style/formatting.
Problem:
Given an array of integers, return indices of the two numbers such
that they add up to a specific target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
My solution:
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
for num_other in num_lst[indx+1:]:
if nums[num] + nums[num_other] == target:
return [num, num_other]
else:
continue
return None
python python-3.x k-sum
$endgroup$
Here's my solution for the Leet Code's Two Sum problem -- would love feedback on (1) code efficiency and (2) style/formatting.
Problem:
Given an array of integers, return indices of the two numbers such
that they add up to a specific target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
My solution:
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
for num_other in num_lst[indx+1:]:
if nums[num] + nums[num_other] == target:
return [num, num_other]
else:
continue
return None
python python-3.x k-sum
python python-3.x k-sum
edited Jan 25 at 17:47


200_success
130k17154419
130k17154419
asked Jan 25 at 17:32
zthomas.nczthomas.nc
295311
295311
2
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06
add a comment |
2
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06
2
2
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06
add a comment |
3 Answers
3
active
oldest
votes
$begingroup$
Code Style
Your code contains a few lines that accomplish nothing and obfuscate your intent:
else:
continue
If the conditional is false, you'll automatically
continue
on to the next iteration without having to tell the program to do that.
return None
All Python functions implicitly
return None
; however, PEP 8 recommends this practice.
num_lst = list(range(len(nums)))
effectively generates a list of all the indices in thenums
input list. Then, you immediatelyenumerate
this list, which produces pairs of identical indicesindx, num
. If all you're attempting to do is iterate, this is significant obfuscation; simply callenumerate
directly onnums
to produce index-element tuples:
def twoSum(self, nums, target):
for i, num in enumerate(nums):
for j in range(i + 1, len(nums)):
if num + nums[j] == target:
return [i, j]
This makes the intent much clearer: there are no duplicate variables with different names representing the same thing. It also saves unnecessary space and overhead associated with creating a list from a range.
- Following on the previous item,
indx, num
andnum_lst
are confusing variable names, especially when they're all actually indices (which are technically numbers).
Efficiency
This code is inefficient, running in quadratic time, or $mathcal{O}(n^2)$. Leetcode is generous to let this pass (but won't be so forgiving in the future!). The reason for this is the nested loop; for every element in your list, you iterate over every other element to draw comparisons. A linear solution should finish in ~65 ms, while this takes ~4400 ms.
Here is an efficient solution that runs in $mathcal{O}(n)$ time:
hist = {}
for i, n in enumerate(nums):
if target - n in hist:
return [hist[target-n], i]
hist[n] = i
How does this work? The magic of hashing. The dictionary
hist
offers constant $mathcal{O}(1)$ lookup time. Whenever we visit a new element innums
, we check to see if its sum complement is in the dictionary; else, we store it in the dictionary as anum => index
pair.
This is the classic time-space tradeoff: the quadratic solution is slow but space efficient, while this solution takes more space but gains a huge boost in speed. In almost every case, choose speed over space.
For completeness, even if you were in a space-constrained environment, there is a fast solution that uses $mathcal{O}(1)$ space and $mathcal{O}(nlog{}n)$ time. This solution is worth knowing about for the practicality of the technique and the fact that it's a common interview follow-up. The way it works is:
- Sort
nums
. - Create two pointers representing an index at 0 and an index at
len(nums) - 1
. - Sum the elements at the pointers.
- If they produce the desired sum, return the pointer indices.
- Otherwise, if the sum is less than the target, increment the left pointer
- Otherwise, decrement the right pointer.
- Go back to step 3 unless the pointers are pointing to the same element, in which case return failure.
- Sort
Be wary of list slicing; it's often a hidden linear performance hit. Removing this slice as the nested loop code above illustrates doesn't improve the quadratic time complexity, but it does reduce overhead.
Now you're ready to try 3 Sum!
$endgroup$
2
$begingroup$
As for returningNone
, see the relevant section of PEP 8.
$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitlyreturn None
". Maybe Python should also putelse: continue
at the end of every loop, just to be explicit :-)
$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
|
show 1 more comment
$begingroup$
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
I'm not sure if I'm missing something, but I think not. I ran this code
nums = [2,5,7,9]
num_lst = list(range(len(nums)))
list(enumerate(num_lst))
output : [(0, 0), (1, 1), (2, 2), (3, 3)]
So why do you create the list and then enumerate it? Maybe what you want to do is simply : enumerate(nums)
then enumerate(nums[index+1:])
on your other loop? A simpler way would be to only use the ranges, as I'll show below.
Also, given your input, there's a possibility that a single number would be higher than the target, in this case you shouldn't make the second iteration.
You also don't need the else: continue
, as it's going to continue
either way.
I'd end up with :
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i1 in range(len(nums)):
if nums[i1] > target:
continue
for i2 in range(i1 + 1, len(nums)):
if nums[i1] + nums[i2] == target:
return [i1, i2]
return None
Without knowing the expected input size, it's hard to focus on performance improvements. The main goal of my review was to remove what seemed like a misunderstanding in your code and in my opinion the code is clearer now.
$endgroup$
1
$begingroup$
Your code is stillO(n**2)
, so I wouldn't say it offers any significant performance boost.
$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/
$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to writetwoSum([1], 2)
, which should returnNone
, not[0, 0]
. The bug is here, my description was incorrect.
$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
add a comment |
$begingroup$
You can use itertools.combinations for a more readable (and likely faster) for
loop. As long as returning a list
isn't a requirement, I would consider it better style to return a tuple
instead. (Especially since it allows you to convey the list length.) Also, as long as the current name isn't a requirement, it is preferable to use snake_case
for function and variable names.
from itertools import combinations
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for (i, first), (j, second) in combinations(enumerate(nums), 2):
if first + second == target:
return [i, j]
return None
$endgroup$
1
$begingroup$
You don't need to createnum_list
anymore. Also,combinations
requires (at least in Python 3.6) a second argumentr
which specifies the length of the combinations. Here,r
should be 2.
$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212228%2fleetcode-two-sum-code-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Code Style
Your code contains a few lines that accomplish nothing and obfuscate your intent:
else:
continue
If the conditional is false, you'll automatically
continue
on to the next iteration without having to tell the program to do that.
return None
All Python functions implicitly
return None
; however, PEP 8 recommends this practice.
num_lst = list(range(len(nums)))
effectively generates a list of all the indices in thenums
input list. Then, you immediatelyenumerate
this list, which produces pairs of identical indicesindx, num
. If all you're attempting to do is iterate, this is significant obfuscation; simply callenumerate
directly onnums
to produce index-element tuples:
def twoSum(self, nums, target):
for i, num in enumerate(nums):
for j in range(i + 1, len(nums)):
if num + nums[j] == target:
return [i, j]
This makes the intent much clearer: there are no duplicate variables with different names representing the same thing. It also saves unnecessary space and overhead associated with creating a list from a range.
- Following on the previous item,
indx, num
andnum_lst
are confusing variable names, especially when they're all actually indices (which are technically numbers).
Efficiency
This code is inefficient, running in quadratic time, or $mathcal{O}(n^2)$. Leetcode is generous to let this pass (but won't be so forgiving in the future!). The reason for this is the nested loop; for every element in your list, you iterate over every other element to draw comparisons. A linear solution should finish in ~65 ms, while this takes ~4400 ms.
Here is an efficient solution that runs in $mathcal{O}(n)$ time:
hist = {}
for i, n in enumerate(nums):
if target - n in hist:
return [hist[target-n], i]
hist[n] = i
How does this work? The magic of hashing. The dictionary
hist
offers constant $mathcal{O}(1)$ lookup time. Whenever we visit a new element innums
, we check to see if its sum complement is in the dictionary; else, we store it in the dictionary as anum => index
pair.
This is the classic time-space tradeoff: the quadratic solution is slow but space efficient, while this solution takes more space but gains a huge boost in speed. In almost every case, choose speed over space.
For completeness, even if you were in a space-constrained environment, there is a fast solution that uses $mathcal{O}(1)$ space and $mathcal{O}(nlog{}n)$ time. This solution is worth knowing about for the practicality of the technique and the fact that it's a common interview follow-up. The way it works is:
- Sort
nums
. - Create two pointers representing an index at 0 and an index at
len(nums) - 1
. - Sum the elements at the pointers.
- If they produce the desired sum, return the pointer indices.
- Otherwise, if the sum is less than the target, increment the left pointer
- Otherwise, decrement the right pointer.
- Go back to step 3 unless the pointers are pointing to the same element, in which case return failure.
- Sort
Be wary of list slicing; it's often a hidden linear performance hit. Removing this slice as the nested loop code above illustrates doesn't improve the quadratic time complexity, but it does reduce overhead.
Now you're ready to try 3 Sum!
$endgroup$
2
$begingroup$
As for returningNone
, see the relevant section of PEP 8.
$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitlyreturn None
". Maybe Python should also putelse: continue
at the end of every loop, just to be explicit :-)
$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
|
show 1 more comment
$begingroup$
Code Style
Your code contains a few lines that accomplish nothing and obfuscate your intent:
else:
continue
If the conditional is false, you'll automatically
continue
on to the next iteration without having to tell the program to do that.
return None
All Python functions implicitly
return None
; however, PEP 8 recommends this practice.
num_lst = list(range(len(nums)))
effectively generates a list of all the indices in thenums
input list. Then, you immediatelyenumerate
this list, which produces pairs of identical indicesindx, num
. If all you're attempting to do is iterate, this is significant obfuscation; simply callenumerate
directly onnums
to produce index-element tuples:
def twoSum(self, nums, target):
for i, num in enumerate(nums):
for j in range(i + 1, len(nums)):
if num + nums[j] == target:
return [i, j]
This makes the intent much clearer: there are no duplicate variables with different names representing the same thing. It also saves unnecessary space and overhead associated with creating a list from a range.
- Following on the previous item,
indx, num
andnum_lst
are confusing variable names, especially when they're all actually indices (which are technically numbers).
Efficiency
This code is inefficient, running in quadratic time, or $mathcal{O}(n^2)$. Leetcode is generous to let this pass (but won't be so forgiving in the future!). The reason for this is the nested loop; for every element in your list, you iterate over every other element to draw comparisons. A linear solution should finish in ~65 ms, while this takes ~4400 ms.
Here is an efficient solution that runs in $mathcal{O}(n)$ time:
hist = {}
for i, n in enumerate(nums):
if target - n in hist:
return [hist[target-n], i]
hist[n] = i
How does this work? The magic of hashing. The dictionary
hist
offers constant $mathcal{O}(1)$ lookup time. Whenever we visit a new element innums
, we check to see if its sum complement is in the dictionary; else, we store it in the dictionary as anum => index
pair.
This is the classic time-space tradeoff: the quadratic solution is slow but space efficient, while this solution takes more space but gains a huge boost in speed. In almost every case, choose speed over space.
For completeness, even if you were in a space-constrained environment, there is a fast solution that uses $mathcal{O}(1)$ space and $mathcal{O}(nlog{}n)$ time. This solution is worth knowing about for the practicality of the technique and the fact that it's a common interview follow-up. The way it works is:
- Sort
nums
. - Create two pointers representing an index at 0 and an index at
len(nums) - 1
. - Sum the elements at the pointers.
- If they produce the desired sum, return the pointer indices.
- Otherwise, if the sum is less than the target, increment the left pointer
- Otherwise, decrement the right pointer.
- Go back to step 3 unless the pointers are pointing to the same element, in which case return failure.
- Sort
Be wary of list slicing; it's often a hidden linear performance hit. Removing this slice as the nested loop code above illustrates doesn't improve the quadratic time complexity, but it does reduce overhead.
Now you're ready to try 3 Sum!
$endgroup$
2
$begingroup$
As for returningNone
, see the relevant section of PEP 8.
$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitlyreturn None
". Maybe Python should also putelse: continue
at the end of every loop, just to be explicit :-)
$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
|
show 1 more comment
$begingroup$
Code Style
Your code contains a few lines that accomplish nothing and obfuscate your intent:
else:
continue
If the conditional is false, you'll automatically
continue
on to the next iteration without having to tell the program to do that.
return None
All Python functions implicitly
return None
; however, PEP 8 recommends this practice.
num_lst = list(range(len(nums)))
effectively generates a list of all the indices in thenums
input list. Then, you immediatelyenumerate
this list, which produces pairs of identical indicesindx, num
. If all you're attempting to do is iterate, this is significant obfuscation; simply callenumerate
directly onnums
to produce index-element tuples:
def twoSum(self, nums, target):
for i, num in enumerate(nums):
for j in range(i + 1, len(nums)):
if num + nums[j] == target:
return [i, j]
This makes the intent much clearer: there are no duplicate variables with different names representing the same thing. It also saves unnecessary space and overhead associated with creating a list from a range.
- Following on the previous item,
indx, num
andnum_lst
are confusing variable names, especially when they're all actually indices (which are technically numbers).
Efficiency
This code is inefficient, running in quadratic time, or $mathcal{O}(n^2)$. Leetcode is generous to let this pass (but won't be so forgiving in the future!). The reason for this is the nested loop; for every element in your list, you iterate over every other element to draw comparisons. A linear solution should finish in ~65 ms, while this takes ~4400 ms.
Here is an efficient solution that runs in $mathcal{O}(n)$ time:
hist = {}
for i, n in enumerate(nums):
if target - n in hist:
return [hist[target-n], i]
hist[n] = i
How does this work? The magic of hashing. The dictionary
hist
offers constant $mathcal{O}(1)$ lookup time. Whenever we visit a new element innums
, we check to see if its sum complement is in the dictionary; else, we store it in the dictionary as anum => index
pair.
This is the classic time-space tradeoff: the quadratic solution is slow but space efficient, while this solution takes more space but gains a huge boost in speed. In almost every case, choose speed over space.
For completeness, even if you were in a space-constrained environment, there is a fast solution that uses $mathcal{O}(1)$ space and $mathcal{O}(nlog{}n)$ time. This solution is worth knowing about for the practicality of the technique and the fact that it's a common interview follow-up. The way it works is:
- Sort
nums
. - Create two pointers representing an index at 0 and an index at
len(nums) - 1
. - Sum the elements at the pointers.
- If they produce the desired sum, return the pointer indices.
- Otherwise, if the sum is less than the target, increment the left pointer
- Otherwise, decrement the right pointer.
- Go back to step 3 unless the pointers are pointing to the same element, in which case return failure.
- Sort
Be wary of list slicing; it's often a hidden linear performance hit. Removing this slice as the nested loop code above illustrates doesn't improve the quadratic time complexity, but it does reduce overhead.
Now you're ready to try 3 Sum!
$endgroup$
Code Style
Your code contains a few lines that accomplish nothing and obfuscate your intent:
else:
continue
If the conditional is false, you'll automatically
continue
on to the next iteration without having to tell the program to do that.
return None
All Python functions implicitly
return None
; however, PEP 8 recommends this practice.
num_lst = list(range(len(nums)))
effectively generates a list of all the indices in thenums
input list. Then, you immediatelyenumerate
this list, which produces pairs of identical indicesindx, num
. If all you're attempting to do is iterate, this is significant obfuscation; simply callenumerate
directly onnums
to produce index-element tuples:
def twoSum(self, nums, target):
for i, num in enumerate(nums):
for j in range(i + 1, len(nums)):
if num + nums[j] == target:
return [i, j]
This makes the intent much clearer: there are no duplicate variables with different names representing the same thing. It also saves unnecessary space and overhead associated with creating a list from a range.
- Following on the previous item,
indx, num
andnum_lst
are confusing variable names, especially when they're all actually indices (which are technically numbers).
Efficiency
This code is inefficient, running in quadratic time, or $mathcal{O}(n^2)$. Leetcode is generous to let this pass (but won't be so forgiving in the future!). The reason for this is the nested loop; for every element in your list, you iterate over every other element to draw comparisons. A linear solution should finish in ~65 ms, while this takes ~4400 ms.
Here is an efficient solution that runs in $mathcal{O}(n)$ time:
hist = {}
for i, n in enumerate(nums):
if target - n in hist:
return [hist[target-n], i]
hist[n] = i
How does this work? The magic of hashing. The dictionary
hist
offers constant $mathcal{O}(1)$ lookup time. Whenever we visit a new element innums
, we check to see if its sum complement is in the dictionary; else, we store it in the dictionary as anum => index
pair.
This is the classic time-space tradeoff: the quadratic solution is slow but space efficient, while this solution takes more space but gains a huge boost in speed. In almost every case, choose speed over space.
For completeness, even if you were in a space-constrained environment, there is a fast solution that uses $mathcal{O}(1)$ space and $mathcal{O}(nlog{}n)$ time. This solution is worth knowing about for the practicality of the technique and the fact that it's a common interview follow-up. The way it works is:
- Sort
nums
. - Create two pointers representing an index at 0 and an index at
len(nums) - 1
. - Sum the elements at the pointers.
- If they produce the desired sum, return the pointer indices.
- Otherwise, if the sum is less than the target, increment the left pointer
- Otherwise, decrement the right pointer.
- Go back to step 3 unless the pointers are pointing to the same element, in which case return failure.
- Sort
Be wary of list slicing; it's often a hidden linear performance hit. Removing this slice as the nested loop code above illustrates doesn't improve the quadratic time complexity, but it does reduce overhead.
Now you're ready to try 3 Sum!
edited Jan 26 at 19:06
answered Jan 25 at 18:41
ggorlenggorlen
383111
383111
2
$begingroup$
As for returningNone
, see the relevant section of PEP 8.
$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitlyreturn None
". Maybe Python should also putelse: continue
at the end of every loop, just to be explicit :-)
$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
|
show 1 more comment
2
$begingroup$
As for returningNone
, see the relevant section of PEP 8.
$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitlyreturn None
". Maybe Python should also putelse: continue
at the end of every loop, just to be explicit :-)
$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
2
2
$begingroup$
As for returning
None
, see the relevant section of PEP 8.$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
As for returning
None
, see the relevant section of PEP 8.$endgroup$
– Solomon Ucko
Jan 26 at 1:48
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitly
return None
". Maybe Python should also put else: continue
at the end of every loop, just to be explicit :-)$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
That's true, Python does say "explicit is better than implicit". I can amend my recommendation to be "at least be aware that Python statements implicitly
return None
". Maybe Python should also put else: continue
at the end of every loop, just to be explicit :-)$endgroup$
– ggorlen
Jan 26 at 1:58
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
Python should, but doesn't know not to copy the entire thing. It has no such optimisation.
$endgroup$
– wizzwizz4
Jan 26 at 16:44
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@wizzwizz4 No lazy copying? E.g. return a pointer in O(1) to the slice element and then wait for mutation to perform a copy? I'd like to update if incorrect here.
$endgroup$
– ggorlen
Jan 26 at 17:20
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
$begingroup$
@ggorlen Apparently not. Try it online! Rule of thumb: Python performs no optimisations at all.
$endgroup$
– wizzwizz4
Jan 26 at 17:54
|
show 1 more comment
$begingroup$
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
I'm not sure if I'm missing something, but I think not. I ran this code
nums = [2,5,7,9]
num_lst = list(range(len(nums)))
list(enumerate(num_lst))
output : [(0, 0), (1, 1), (2, 2), (3, 3)]
So why do you create the list and then enumerate it? Maybe what you want to do is simply : enumerate(nums)
then enumerate(nums[index+1:])
on your other loop? A simpler way would be to only use the ranges, as I'll show below.
Also, given your input, there's a possibility that a single number would be higher than the target, in this case you shouldn't make the second iteration.
You also don't need the else: continue
, as it's going to continue
either way.
I'd end up with :
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i1 in range(len(nums)):
if nums[i1] > target:
continue
for i2 in range(i1 + 1, len(nums)):
if nums[i1] + nums[i2] == target:
return [i1, i2]
return None
Without knowing the expected input size, it's hard to focus on performance improvements. The main goal of my review was to remove what seemed like a misunderstanding in your code and in my opinion the code is clearer now.
$endgroup$
1
$begingroup$
Your code is stillO(n**2)
, so I wouldn't say it offers any significant performance boost.
$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/
$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to writetwoSum([1], 2)
, which should returnNone
, not[0, 0]
. The bug is here, my description was incorrect.
$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
add a comment |
$begingroup$
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
I'm not sure if I'm missing something, but I think not. I ran this code
nums = [2,5,7,9]
num_lst = list(range(len(nums)))
list(enumerate(num_lst))
output : [(0, 0), (1, 1), (2, 2), (3, 3)]
So why do you create the list and then enumerate it? Maybe what you want to do is simply : enumerate(nums)
then enumerate(nums[index+1:])
on your other loop? A simpler way would be to only use the ranges, as I'll show below.
Also, given your input, there's a possibility that a single number would be higher than the target, in this case you shouldn't make the second iteration.
You also don't need the else: continue
, as it's going to continue
either way.
I'd end up with :
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i1 in range(len(nums)):
if nums[i1] > target:
continue
for i2 in range(i1 + 1, len(nums)):
if nums[i1] + nums[i2] == target:
return [i1, i2]
return None
Without knowing the expected input size, it's hard to focus on performance improvements. The main goal of my review was to remove what seemed like a misunderstanding in your code and in my opinion the code is clearer now.
$endgroup$
1
$begingroup$
Your code is stillO(n**2)
, so I wouldn't say it offers any significant performance boost.
$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/
$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to writetwoSum([1], 2)
, which should returnNone
, not[0, 0]
. The bug is here, my description was incorrect.
$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
add a comment |
$begingroup$
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
I'm not sure if I'm missing something, but I think not. I ran this code
nums = [2,5,7,9]
num_lst = list(range(len(nums)))
list(enumerate(num_lst))
output : [(0, 0), (1, 1), (2, 2), (3, 3)]
So why do you create the list and then enumerate it? Maybe what you want to do is simply : enumerate(nums)
then enumerate(nums[index+1:])
on your other loop? A simpler way would be to only use the ranges, as I'll show below.
Also, given your input, there's a possibility that a single number would be higher than the target, in this case you shouldn't make the second iteration.
You also don't need the else: continue
, as it's going to continue
either way.
I'd end up with :
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i1 in range(len(nums)):
if nums[i1] > target:
continue
for i2 in range(i1 + 1, len(nums)):
if nums[i1] + nums[i2] == target:
return [i1, i2]
return None
Without knowing the expected input size, it's hard to focus on performance improvements. The main goal of my review was to remove what seemed like a misunderstanding in your code and in my opinion the code is clearer now.
$endgroup$
num_lst = list(range(len(nums)))
for indx, num in enumerate(num_lst):
I'm not sure if I'm missing something, but I think not. I ran this code
nums = [2,5,7,9]
num_lst = list(range(len(nums)))
list(enumerate(num_lst))
output : [(0, 0), (1, 1), (2, 2), (3, 3)]
So why do you create the list and then enumerate it? Maybe what you want to do is simply : enumerate(nums)
then enumerate(nums[index+1:])
on your other loop? A simpler way would be to only use the ranges, as I'll show below.
Also, given your input, there's a possibility that a single number would be higher than the target, in this case you shouldn't make the second iteration.
You also don't need the else: continue
, as it's going to continue
either way.
I'd end up with :
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for i1 in range(len(nums)):
if nums[i1] > target:
continue
for i2 in range(i1 + 1, len(nums)):
if nums[i1] + nums[i2] == target:
return [i1, i2]
return None
Without knowing the expected input size, it's hard to focus on performance improvements. The main goal of my review was to remove what seemed like a misunderstanding in your code and in my opinion the code is clearer now.
edited Jan 29 at 19:24
answered Jan 25 at 18:20


IEatBagelsIEatBagels
8,98323378
8,98323378
1
$begingroup$
Your code is stillO(n**2)
, so I wouldn't say it offers any significant performance boost.
$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/
$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to writetwoSum([1], 2)
, which should returnNone
, not[0, 0]
. The bug is here, my description was incorrect.
$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
add a comment |
1
$begingroup$
Your code is stillO(n**2)
, so I wouldn't say it offers any significant performance boost.
$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/
$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to writetwoSum([1], 2)
, which should returnNone
, not[0, 0]
. The bug is here, my description was incorrect.
$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
1
1
$begingroup$
Your code is still
O(n**2)
, so I wouldn't say it offers any significant performance boost.$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Your code is still
O(n**2)
, so I wouldn't say it offers any significant performance boost.$endgroup$
– Eric Duminil
Jan 26 at 15:12
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with
0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
Also, your code has a few bugs. It doesn't work with negative numbers, it doesn't even work with
0
reliably (twoSum([2,0], 2)
) and it uses the same number twice (twoSum([1, 1], 2)
). :-/$endgroup$
– Eric Duminil
Jan 26 at 15:16
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
$begingroup$
@EricDuminil The latter is fine; number != element.
$endgroup$
– wizzwizz4
Jan 26 at 16:46
1
1
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to write
twoSum([1], 2)
, which should return None
, not [0, 0]
. The bug is here, my description was incorrect.$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@wizzwizz4: Thanks for the comment. You're right. I meant to write
twoSum([1], 2)
, which should return None
, not [0, 0]
. The bug is here, my description was incorrect.$endgroup$
– Eric Duminil
Jan 26 at 16:53
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
$begingroup$
@EricDuminil I mainly wanted to focus on some of the bloat to simplify it, went fast and introduced bugs, lol. And without the expected size of input it's hard to tell if there's a real performance value to my answer (and to any other one at that, if we always expect 4 numbers, performance isn't really an issue). I also wrongfully assumed that we dealt with positive non-zero integers.
$endgroup$
– IEatBagels
Jan 29 at 19:23
add a comment |
$begingroup$
You can use itertools.combinations for a more readable (and likely faster) for
loop. As long as returning a list
isn't a requirement, I would consider it better style to return a tuple
instead. (Especially since it allows you to convey the list length.) Also, as long as the current name isn't a requirement, it is preferable to use snake_case
for function and variable names.
from itertools import combinations
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for (i, first), (j, second) in combinations(enumerate(nums), 2):
if first + second == target:
return [i, j]
return None
$endgroup$
1
$begingroup$
You don't need to createnum_list
anymore. Also,combinations
requires (at least in Python 3.6) a second argumentr
which specifies the length of the combinations. Here,r
should be 2.
$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
add a comment |
$begingroup$
You can use itertools.combinations for a more readable (and likely faster) for
loop. As long as returning a list
isn't a requirement, I would consider it better style to return a tuple
instead. (Especially since it allows you to convey the list length.) Also, as long as the current name isn't a requirement, it is preferable to use snake_case
for function and variable names.
from itertools import combinations
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for (i, first), (j, second) in combinations(enumerate(nums), 2):
if first + second == target:
return [i, j]
return None
$endgroup$
1
$begingroup$
You don't need to createnum_list
anymore. Also,combinations
requires (at least in Python 3.6) a second argumentr
which specifies the length of the combinations. Here,r
should be 2.
$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
add a comment |
$begingroup$
You can use itertools.combinations for a more readable (and likely faster) for
loop. As long as returning a list
isn't a requirement, I would consider it better style to return a tuple
instead. (Especially since it allows you to convey the list length.) Also, as long as the current name isn't a requirement, it is preferable to use snake_case
for function and variable names.
from itertools import combinations
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for (i, first), (j, second) in combinations(enumerate(nums), 2):
if first + second == target:
return [i, j]
return None
$endgroup$
You can use itertools.combinations for a more readable (and likely faster) for
loop. As long as returning a list
isn't a requirement, I would consider it better style to return a tuple
instead. (Especially since it allows you to convey the list length.) Also, as long as the current name isn't a requirement, it is preferable to use snake_case
for function and variable names.
from itertools import combinations
def twoSum(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
for (i, first), (j, second) in combinations(enumerate(nums), 2):
if first + second == target:
return [i, j]
return None
edited Jan 26 at 15:03
answered Jan 26 at 1:59
Solomon UckoSolomon Ucko
1,1751415
1,1751415
1
$begingroup$
You don't need to createnum_list
anymore. Also,combinations
requires (at least in Python 3.6) a second argumentr
which specifies the length of the combinations. Here,r
should be 2.
$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
add a comment |
1
$begingroup$
You don't need to createnum_list
anymore. Also,combinations
requires (at least in Python 3.6) a second argumentr
which specifies the length of the combinations. Here,r
should be 2.
$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
1
1
$begingroup$
You don't need to create
num_list
anymore. Also, combinations
requires (at least in Python 3.6) a second argument r
which specifies the length of the combinations. Here, r
should be 2.$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
You don't need to create
num_list
anymore. Also, combinations
requires (at least in Python 3.6) a second argument r
which specifies the length of the combinations. Here, r
should be 2.$endgroup$
– Schmuddi
Jan 26 at 9:31
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
$begingroup$
Oops, thanks for pointing those out.
$endgroup$
– Solomon Ucko
Jan 26 at 15:02
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212228%2fleetcode-two-sum-code-in-python%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
$begingroup$
Would any of the lists contain negative numbers?
$endgroup$
– MSeifert
Jan 26 at 14:00
$begingroup$
@MSeifert I don't know, but feel free to assume yes
$endgroup$
– zthomas.nc
Jan 27 at 18:06