Skip to content

Instantly share code, notes, and snippets.

@gi11es
Last active March 9, 2022 20:21
Show Gist options
  • Save gi11es/7709c00127a7a45d3eddbfc8eee66544 to your computer and use it in GitHub Desktop.
Save gi11es/7709c00127a7a45d3eddbfc8eee66544 to your computer and use it in GitHub Desktop.
My solution to the 3SUM https://en.wikipedia.org/wiki/3SUM puzzle on https://leetcode.com/problems/3sum/ which runs faster than 99.91% of previous submissions https://leetcode.com/submissions/detail/656602954/ Too good to be correct?
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
result = []
negativeDict = {} # Hash map. keys are the negative values found in the list and values are how many times they occur
positiveDict = {} # Same for positive values
zeroCount = 0 # How many zeros are in the list
# Go through the list once to populate the hash maps described above and count zeros - complexity: O(n)
length = len(nums)
for i in range(length):
current = nums[i]
if current == 0:
zeroCount += 1
elif current < 0:
if -current in negativeDict:
negativeDict[-current] += 1
else:
negativeDict[-current] = 1
else:
if current in positiveDict:
positiveDict[current] += 1
else:
positiveDict[current] = 1
# Handle the special case of at least three zeros being in the list. in that case [0, 0, 0] is a valid solution
if zeroCount >= 3:
result.append([0, 0, 0])
previousNegatives = []
for negative in negativeDict:
# Handle the special case of zero being one of the digits in a valid solution
# This means that the other two digits have to be one negative number a and one positive number b where a = -b
# Looking this up in the positive hash map has a cost of O(1)
if zeroCount > 0 and negative in positiveDict:
result.append([-negative, 0, negative])
# Handle the special case of having 2 or more of the same negative number a
# This means we can attempt to pair it to a positive number whose value is -2 * a
# Looking this up in the positive hash map has a cost of O(1)
value = negativeDict[negative]
if value > 1:
if negative * 2 in positiveDict:
result.append([-negative, -negative, negative * 2])
# If the 2 negative numbers that can make up a trio aren't the same, they have to be different!
# We check every unique combination of 2 different negative numbers.
# This is achieved by combining the current number (since they're the keys to the hash map, they're unique)
# with every negative number that has been iterated through before. This ensures that we never look at the same
# pair of two unique negative numbers more than once.
for previousNegative in previousNegatives:
if negative + previousNegative in positiveDict:
result.append([-negative, -previousNegative, negative + previousNegative])
previousNegatives.append(negative)
previousPositives = []
# At this point we've covered:
# - Any combination that involves zeros, since you can't total zero with 2 zeros and a non-zero number
# - Any combination with 2 negative numbers and 1 positive number
# Since you can't total zero with 3 negative numbers or with 3 positive numbers, all we have left to do is look at
# combinations of 2 positive numbers and 1 negative number. This is easily achieved below by mirroring the logic
# above, minus the lookup for the case with 1 zero, as all of those would have been found thanks to the negative
# counterpart already.
for positive in positiveDict:
value = positiveDict[positive]
if value > 1:
if positive * 2 in negativeDict:
result.append([-positive * 2, positive, positive])
for previousPositive in previousPositives:
if positive + previousPositive in negativeDict:
result.append([-positive - previousPositive, positive, previousPositive])
previousPositives.append(positive)
# Total runtime complexity in the worst case? O(2 * n + n * (2 + (n - 1) / 2))
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment