«индекс списка вне диапазона» в цикле while предназначен для возврата двух значений из списка, которые добавляются к определенной сумме

Строка 11 выдает ошибку. Пошаговое выполнение кода не выявило проблемы? Код просто указывает на левый и правый концы списка, перемещая указатели к каждой итерации, пока не будет найдена целевая сумма или нет! Не похоже, что петли могут наступать сами на себя, но, похоже, в любом случае.

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)

person user2970900    schedule 27.12.2016    source источник


Ответы (2)


это то, что я изменил:

  • array[len(array)-1] -> len(array)-1 (вот что вызвало ваш IndexError)
  • indx_Dict: я изменил так, что indx_Dict[sorted_index] = original_index
  • sum -> sum_: sum является встроенным. никогда не рекомендуется использовать одно из них в качестве имени переменной! (да, новое имя могло бы быть лучше)

это окончательный код:

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

вот обсуждение этой проблемы: ">Найти 2 числа в несортированном массиве, равные заданной сумме (о чем вы, кажется, знаете - похоже на то, что вы пытаетесь сделать). это версия python только этого:

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

эта версия основана на переборе индексов i и j.

теперь вот версия, которая, как мне кажется, более питоническая (но, может быть, немного сложнее для понимания, но она делает то же самое, что и выше). он полностью игнорирует индекс j, так как он на самом деле не нужен:

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

ааааи просто для удовольствия: всякий раз, когда в игре есть отсортированный список, я чувствую необходимость использовать bisect. (очень элементарный тест показал, что это может работать лучше для n > 10'000'000; n — это длина списка, поэтому, возможно, не стоит этого для всех практических целей...)

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

для (немного больше) полноты: существует подход, основанный на словаре:

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

я надеюсь, что код служит своим собственным объяснением...

person hiro protagonist    schedule 27.12.2016
comment
Проблема в том, что l — это значение, а r — это индекс; это приведет к той же ошибке, что и у OP. - person 17slim; 27.12.2016
comment
@17slim: в моей версии r и l являются индексами. исключительно. что заставляет вас думать иначе? как возникла такая же ошибка? (признаюсь, пришлось исправить небольшую ошибку...) - person hiro protagonist; 27.12.2016
comment
Небольшая ошибка, которая разрешила мою жалобу (переключение l = array[0] на l = 0): P..... +1 за исправление части словаря, а не за его удаление, как я. - person 17slim; 27.12.2016
comment
Хотя я все еще сомневаюсь в логике OP с операторами elif/else, не уверен, почему быть меньше или больше суммы связано с тем, какой индекс нужно изменить. Я также вижу, что это приводит к пропущенным комбинациям значений. - person 17slim; 28.12.2016
comment
@17slim: я согласен. я просто хотел указать, что пошло не так; других улучшений не искал. тут уже поздно... - person hiro protagonist; 28.12.2016

l и r - это не ваши индексы, а значения из вашего массива.

Скажем, у вас есть массив: [21,22,23,23]. l 21 год, r 23 года; поэтому вызов array[21] выходит за рамки допустимого.

Кроме того, у вас могут возникнуть проблемы с вашим indx_Dict. Вы вызываете на нем enumerate, который возвращает [(0,21),...(3,23)]. Звонок dict дает вам {0:21,1:22,2:23,3:23}. Нет ключа, эквивалентного 21 или 23, что также выдаст вам ошибку.

Что вы можете попробовать:

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)

Таким образом, ваши l и r являются индексами отсортированного array. Он перебирает все возможные комбинации значений из массива и возвращается, когда либо находит сумму, либо перебирает все. Затем он возвращает индекс исходного num_array, который содержит правильные значения.

Кроме того, как сказал @hiro-protagonist, sum уже является встроенной функцией в Python, поэтому ее следует изменить на что-то другое (asum в моем примере).

person 17slim    schedule 27.12.2016