Найдите наименьшее число, которое больше заданного числа в отсортированном списке

учитывая отсортированный список чисел, мне нужно найти наименьшее число, которое больше заданного числа. Рассмотрим этот список:


arr=[1,2,3,5,7,11,101,131,151,181,191,313,353,373,383]

скажем, указанное число равно 320. Затем мой метод должен вернуть 353, поскольку 353-наименьшее число, большее 320.

Я пытаюсь использовать слегка измененную форму двоичного поиска; однако при выполнении программа переходит в бесконечный цикл.


def modBinarySearch(arr,x):
    l=len(arr)
    mid=l/2
    if arr[mid]>=x and arr[mid-1]<x:
        return arr[mid]
    elif arr[mid]>x and arr[mid-1]>x:
        modBinarySearch(arr[mid:l],x)
    else: 
        modBinarySearch(arr[0:mid],x)

N=int(raw_input())
arr=[1,2,3,5,7,11,101,131,151,181,191,313,353,373,383]
print modBinarySearch(arr,N)

может кто-нибудь указать, что я делаю не так ?

8 ответов


Если arr[mid] и arr[mid-1], оба больше, чем ваше число, вы должны искать в arr[0:mid], не так ли?

 elif arr[mid]>x and arr[mid-1]>x:
    modBinarySearch(arr[0:mid],x)
else: 
    modBinarySearch(arr[mid:1],x)

существует стандартный модуль,bisect, что уже делает это:

In [49]: arr[bisect.bisect(arr, 320)]
Out[49]: 353

Я думаю, что это должен быть метод go-to для поиска отсортированных списков. Есть несколько примеры в руководстве.

Что касается вашей реализации, существует ряд проблем:

  1. ваша рекурсия неправильно обрабатывает небольшие массивы.
  2. нарезка, выполненная во второй ветви, неверна.
  3. ваша функция ничего не возвращает.
  4. , потому что arr в порядке возрастания, arr[mid]>x and arr[mid-1]>x эквивалентно arr[mid-1]>x, предполагая, что вы не написали, что вы имели в виду

и последнее, но не менее важное: рекурсия и все это нарезание совершенно не нужны для этой проблемы.


Если размер ваших списков будет 15, отбросьте двоичный поиск вообще и используйте последовательный поиск.

вы найдете код намного проще писать, и, если вам не нужно делать это много миллионов раз в секунду, последовательное решение будет достаточно быстрым.

Если вы do нужно придерживаться двоичного поиска, ваш первый шаг должен быть фактически возвращать результаты ваших рекурсивных вызовов.


def modBinarySearch(arr, n):
    m = len(arr) / 2

    if arr[m] >= n and arr[m - 1] < n:
        return arr[m]
    elif arr[m] > n and arr[m - 1] > n:
        return modBinarySearch(arr[:m], n)
    else:
        return modBinarySearch(arr[m:], n)


arr = [1, 2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383]
n = 320
print(modBinarySearch(arr, n))

     python 3.2

     next(i for  i in arr if i>320)

на модуль bisect ваш самый лучший выбор для этого:

from bisect import bisect_left, bisect_right

arr=[1,2,3,5,7,11,101,131,151,181,191,313,353,373,383]


def find_lt(a, x):
    'Find rightmost value less than x'
    i = bisect_left(a, x)
    if i:
        return a[i-1]
    raise ValueError

def find_gt(a, x):
    'Find leftmost value greater than x'
    i = bisect_right(a, x)
    if i != len(a):
        return a[i]
    raise ValueError

print find_lt(arr,320)          
print find_gt(arr,320)  

печать

313
353     

Если список отсортирован:

x = range(20)
N= 15

for i in x:
    if i>N:
        print i
        break

дает 16.

при использовании numpy:

x = np.arange(20)
N = 15
x[x>15][0]

дает 16.

Если вы искали легкие реализации, для вашей конкретной проблемы, позвольте мне вернуться к этому.


def modBinarySearch(arr,x):
    l=len(arr)
    mid=l/2
    if arr[mid] >= x and arr[mid-1] < x:
        return arr[mid]
    elif arr[mid]>x and arr[mid-1]>x:
        num = modBinarySearch(arr[0:mid],x)
    else:
        num = modBinarySearch(arr[mid:l],x)
    return num

N=int(raw_input('Enter a number: '))
arr=[1, 2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383]
print modBinarySearch(arr,N)