0

I am working on the Two Sums question from Leetcode, where you have to find the indices of the two numbers that add up to the target.

In the question statement three examples were given to check for: nums = [2,7,11,15] & target = 9 (should output [0,1]), nums = [3,2,4] & target = 6 (should output [1,2]) and finally nums = [3,3] & target = 6 (should output [0,1]). The order of the output is said to not be important. Link to question

My code works perfectly for the first two situations, however for nums = [3,3] & target = 6 it returns [0, 0] instead of the desired [0,1]. I think the error is because nums.index(j) in my code returns the index for the very first value of 3 it finds, so 0 instead of the desired 1.

Is there a way to fix this without having to change the entire code? (so to get the correct index in case of duplicates in the nums list?)

Thank you in advance!

This is my code:

class Solution:
    def twoSum (output, nums, target):
        output = []
        for i in range(len(nums)):
            for j in nums[i+1:]:
                if nums[i]+j == target:
                    output.append(i)
                    output.append(nums.index(j))
        return output
Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70
Lily
  • 1
  • Also, comments and tips on how to improve my code are always welcome as I am a beginner programmer! :) Thank you! – Lily Jul 01 '21 at 15:21
  • I don't understand your code, why do you have a second loop through i+1: ? – TheChicken4452 Jul 01 '21 at 15:22
  • So that it constantly sums the value at index i with the value of the next index (i+1). It does this for each i. So at the beginning, when i is 0 it sums the zeroth element of the nums list with the first element, then when i is 1 it sums the first element with the second element etc. – Lily Jul 01 '21 at 15:27
  • 3
    Does this answer your question? [Find the index of the second occurrence of a string inside a list](https://stackoverflow.com/questions/18584355/find-the-index-of-the-second-occurrence-of-a-string-inside-a-list) Sure, you aren't asking about a string but you get the point... – Pranav Hosangadi Jul 01 '21 at 15:36

4 Answers4

1

One issue is that is uses index. There are two problems with that: (1) It will always find the first instance of a value in a list, which isn't always what you want if the list contains duplicates, and (2) It's extremely inefficient for large lists, since it effectively creates a third, inner loop when only two loops are needed.

Another issue was the useless first argument output, which was unused, so I deleted it. I also changed it to return as soon as a solution is found. The original posted code just kept searching, which was unnecessary (given the problem description), and even if it did find additional solutions, just appending the indices to the old ones didn't seem to make sense.

The following is what you want:

def twoSum(nums, target):
    for i in range(len(nums)):
        for j in range(i+1, len(nums)):
            if nums[i]+nums[j] == target:
                return [i, j]
    return None

Here's the sample output:

>>> twoSum([2, 7, 11, 15], 9)
[0, 1]
>>> 

>>> twoSum([3, 2, 4], 6)
[1, 2]
>>>

>>> twoSum([3, 3], 6)
[0, 1]
>>> 
Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
1

nums.index(j) will find the index of the first 3 in the list. Which happens to be 0. So you get 0, 0 as the answer.

index() happens to have a start parameter. You can use it to exclude the first 3 from the search.

def twoSum (output, nums, target):
    output = []
    for i in range(len(nums)):
        for j in nums[i+1:]:
            if nums[i]+j == target:
                output.append(i)
                output.append(nums.index(j, start=i+1))
    return output

This is however, quite wasteful. You need not search the list for j again if you had iterated over the indexes from i+1 in the first place:

Also the question mentions that there is only one solution, so you can break early.

def twoSum (output, nums, target):
    output = []
    for i in range(len(nums)):
        for j in range(i+1, len(nums):
            if nums[i]+nums[j] == target:
                output.append(i)
                output.append(j)
                return output

While this is better, it's still not optimal. We need to check each of the n**2 pairs. We can improve the runtime by using extra memory.

def twoSum (output, nums, target):
    reverse_lookup = {n : i for i, n in enumerate(nums)}. # store value to index in map
    for i, n in enumerate(nums):
       if (target - n) in reverse_lookup:  # check if the remaining value is present in the array
           return [i, reverse_lookup[target-n]]

This only need to check each value once & hence is optimal.

rdas
  • 20,604
  • 6
  • 33
  • 46
0

This isn't a good algorithm but to fix it anyway:

def twoSum(nums, target):
    for i in range(len(nums)):
        for j in nums[i + 1:]:
            if nums[i] + j == target:
                return [i, nums[i+1:].index(j)+ i+1]  ## <====

twoSum([3,3], 6)
>> [0, 1]
twoSum([2,7,11,15], 9)
>> [0, 1]
twoSum([3,2,4], 6)
>> [1, 2]

In the second loop you only take the set of remaining numbers in nums and you want the index of that, but when getting the index in the second .append, you are using the whole nums list, which isn't what you want.

Also, since .index is now calculating based on the subset, you should add i+1, to make it fit to the whole nums list.

hint: avoid nested loop, seek complement ;)

Stryder
  • 848
  • 6
  • 9
  • 1
    This will add repititive index if there are more than one duplicates in the list nums. – user215865 Jul 02 '21 at 14:51
  • You are right, and I did fix it. Although, I would argue that in the actual problem that the question links to, it states: 'You may assume that each input would have *exactly one* solution' so more than one duplicates shouldn't really be a concern. But thank you. (now the very inefficient algorithm is also slightly less inefficient :) ) – Stryder Jul 02 '21 at 15:06
0

This covers all the duplicate values. Just modified your code using enumerate. Index will always give you the first index of the value, it will never give you the index for duplicate values. You can either use len(list) or enumerate to find index of duplicate values in a list.

nums = [2,3,2,3,5,6,3]
target = 5
output = []
for i in range(len(nums)):
    for index,j in enumerate(nums[i+1:]):
        if nums[i]+j == target:
            index1 = i
            index2 = index+i+1
            if index1 not in output:
                output.append(index1)
            if index2 not in output:
                output.append(index2)
user215865
  • 476
  • 4
  • 10