1

Line 11 produces the error. Stepping through the code doesn't reveal a problem? The code just points at from left and right ends of list, moving pointers toward per iteration until a target sum is found or not! Doesn't look like the loops can step on itself but seems to anyway.

def twoSum(num_array, sum):
    '''1.twoSum 
    Given an array of integers, return indices of the two numbers that
    add up to a specific target.
    '''
    array = sorted(num_array)
    l = array[0]
    r = array[len(array)-1]
    indx_Dict = dict(enumerate(array))
    while (l < r) :
        if (array[l] + array[r]) == sum:
                return [indx_Dict[l], indx_Dict[r]]
        elif array[l] + array[r] < sum:
            l += 1
        else:
            r -= 1

num_array1 = [2, 7, 11, 15,1,0]
target1 = 9 

twoSum(num_array1, target1)
user2970900
  • 195
  • 2
  • 11

2 Answers2

1

that is what i changed:

  • array[len(array)-1] -> len(array)-1 (that's what caused your IndexError)
  • indx_Dict: i changed it such that indx_Dict[sorted_index] = original_index
  • sum -> sum_: sum is a built-in. it is never a good idea to use one of those as variable name! (yes, the new name could be better)

this is the final code:

def two_sum(num_array, sum_):
    '''1.twoSum
    Given an array of integers, return indices of the two numbers that
    add up to a specific target.
    '''
    array = sorted(num_array)
    l = 0
    r = len(array)-1
    indx_Dict = {array.index(val): index for index, val in enumerate(num_array)}  ##
    while (l < r) :
        if (array[l] + array[r]) == sum_:
             return [indx_Dict[l], indx_Dict[r]]
        elif array[l] + array[r] < sum_:
            l += 1
        else:
            r -= 1

here is a discussion about this problem: Find 2 numbers in an unsorted array equal to a given sum (which you seem to be aware of - looks like what you are trying to do). this is a python version of just that:

def two_sum(lst, total):

    sorted_lst = sorted(lst)
    n = len(lst)
    for i, val0 in enumerate(sorted_lst):
        for j in range(n-1, i, -1):
            val1 = sorted_lst[j]
            s = val0 + val1
            if s < total:
                break
            if s == total:
                return sorted((lst.index(val0), lst.index(val1)))
    return None

this version is based on looping over the indices i and j.

now here is a version that i feel is more pythonic (but maybe a little bit harder to understand; but it does the exact same as the one above). it ignores the index j completely as it is not really needed:

from itertools import islice

def two_sum(lst, total):
    n = len(lst)
    sorted_lst = sorted(lst)
    for i, val0 in enumerate(sorted_lst):
        for val1 in islice(reversed(sorted_lst), n-i):
            s = val0 + val1
            if s < total:
                break
            if s == total:
                return sorted((lst.index(val0), lst.index(val1)))
    return None

aaaaand just for the fun of it: whenever there is a sorted list in play i feel the need to use the bisect module. (a very rudimentary benchmark showed that this may perform better for n > 10'000'000; n being the length of the list. so maybe not worth it for all practical purposes...)

def two_sum_binary(lst, total):
    n = len(lst)
    sorted_lst = sorted(lst)
    for i, val0 in enumerate(sorted_lst):
        # binary search in sorted_lst[i:]
        j = bisect_left(sorted_lst, total-val0, lo=i)
        if j >= n:
            continue
        val1 = sorted_lst[j]
        if val0 + val1 == total:
            return sorted((lst.index(val0), lst.index(val1)))
        else:
            continue
    return None

for (a bit more) completeness: there is a dictionary based approach:

def two_sum_dict(lst, total):
    dct = {val: index for index, val in enumerate(lst)}
    for i, val in enumerate(lst):
        try:
            return sorted((i, dct[total-val]))
        except KeyError:
            pass
    return None

i hope the code serves as its own explanation...

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
  • The problem with this is that `l` is a value, and `r` is an index; this will result in the exact same error the OP is already having. – 17slim Dec 27 '16 at 20:52
  • @17slim: in my version `r` and `l` are indices. exclusively. what makes you think otherwise? how did the same error occur? (i admit, had to fix a minor bug...) – hiro protagonist Dec 27 '16 at 20:56
  • A minor bug that resolved my complaint (switching `l = array[0]` to `l = 0`) :P..... +1 for fixing the dictionary part rather than removing it as I did. – 17slim Dec 27 '16 at 20:59
  • Although I still question the OP's logic with the `elif/else` statements, not sure why being less than or greater than the sum has to do with which index to change. I can also see that resulting in skipped combinations of values. – 17slim Dec 27 '16 at 21:00
  • @17slim: i agree. i just wanted to point out what went wrong; didn't look for other imrovement. it's getting late here... – hiro protagonist Dec 27 '16 at 21:04
0

l and r are not your indices, but values from your array.

Say you have an array: [21,22,23,23]. l is 21, r is 23; therefore, calling array[21] is out of bounds.

Additionally, you would have a problem with your indx_Dict. You call enumerate on it, which returns [(0,21),...(3,23)]. Calling dict gives you {0:21,1:22,2:23,3:23}. There is no key equivalent to 21 or 23, which will also give you an error.

What you could try is:

def twoSum(num_array, asum):
    '''1.twoSum 
    Given an array of integers, return indices of the two numbers that
    add up to a specific target.
    '''
    array = sorted(num_array)
    l = 0
    r = len(array)-1
    while (l < len(array)-1) :
        while (r > l):
            if (array[l] + array[r]) == asum:
                return [num_array.index(array[l]),\
                        num_array.index(array[r])]
            r -= 1
        r = len(array)-1
        l += 1

num_array1 = [2, 7, 11, 15,1,0]
target1 = 9 

twoSum(num_array1, target1)

This way, your l and r are both indices of the sorted array. It goes through every possible combination of values from the array, and returns when it either has found the sum or gone through everything. It then returns the index of the original num_array that contains the correct values.

Also, as @hiro-protagonist said, sum is a built-in function in Python already, so it should be changed to something else (asum in my example).

17slim
  • 1,233
  • 1
  • 16
  • 21