0

For the two sum problems, find two numbers in a list that adds up to the target.

My solution is to create a dictionary/hash_table, and then store everything in it as (value, index) [Note: For duplicate numbers in the list: higher index would override lower index]

Then traverse through the list again to find the other item.

def twoSum(nums, target): 
    lookup = dict((v, i) for i, v in enumerate(nums))
    for i, v in enumerate(nums):
        if target - v in lookup and i != lookup[target-v]:
            return [lookup[target - v], i]

I think the above algorithm would take O(n * n/2) =, hence O(n^2) time but I see some others say that it only takes linear time. Can someone confirm on this?

5
  • Why n/2? Also, why do you think it multiplies? It should add.
    – cs95
    Commented Sep 23, 2017 at 18:12
  • Because store everything in the lookup dictionary would take O(n) and I would have to iterate through at least half of the list to find the item if there's one exist, then it would take O(n/2).
    – jen007
    Commented Sep 23, 2017 at 18:17
  • Oh, I see. It should be O(n) + O(n/2) If there's a solution; O(n) + O(n) if there's no such pair exist.
    – jen007
    Commented Sep 23, 2017 at 18:18
  • Consider the worst case. It's O(n). O(n) + O(n) is linear only.
    – cs95
    Commented Sep 23, 2017 at 18:19
  • O(N/2) is O(N). You don't carry constant coefficients in big O. Commented Sep 23, 2017 at 18:19

1 Answer 1

4

That algorithm takes constant time because the operation target - v in lookup runs in constant time. There is only one depth of for loop.

def twoSum(nums, target):
    lookup = dict((v, i) for i, v in enumerate(nums)) # N
    for i, v in enumerate(nums):  # N
        if target - v in lookup and i != lookup[target - v]: # average constant
            return [lookup[target - v], i]  # constant

If you perform an O(N) operation followed by another O(N) operation, the sequence is still O(N).

Here we're talking only about average time complexity. It's possible to have a really bad hashing function with a lot of collisions, such that target - v in lookup actually takes O(N) time, so the worst-case complexity is actually O(N^2). But with a dict you're unlikely to run into this scenario.

6
  • Because O(n) + O(n) = 2O(n) which for large n is dominated by n, so we always drop any constant in the limit. Commented Sep 23, 2017 at 18:22
  • actually this answer is not correct. The average time complexity is O(N), but worst is O(N^2), as python dictionaries are hashtables, which can still take O(N) to read an element. wiki.python.org/moin/TimeComplexity
    – lejlot
    Commented Sep 23, 2017 at 18:23
  • Not exactly, it's because your head would explode if you actually wanted to compute the coefficient, so instead we drop it and think only about the scaling. Is 5*5 O(1)? Is 5^5 also O(1)? It takes more operations. You're right, @lejlot! I've been assuming we're all talking about average complexity. I'll expand on the answer. Commented Sep 23, 2017 at 18:25
  • So the average is O(n) and the worst case is still O(n^2) due to python dictionary implementation?
    – jen007
    Commented Sep 23, 2017 at 18:26
  • 2
    @jen007 Looking up a value in a hash table is basically never O(n). The only real-world situations where it arises are (a) poorly written custom hash functions and (b) attackers constructing hash-table-breaking data to intentionally use up resources. For general purposes, it's safe to assume that hash table lookups are O(1) (plus the cost of computing the hash, if that is significant).
    – Sneftel
    Commented Sep 23, 2017 at 18:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.