找到预排序数组中给定值的最低索引

时间:2012-04-13 21:58:09

标签: python algorithm

嘿,我在接受采访时有这个问题,并想知道解决问题的最佳方法是什么。所以说你得到一个已经排序的数组,你想要找到某个值x的最低索引。

这是我想出的python /伪代码,我只是想知道是否有更好的方法可以解决它?

def findLowestIndex(arr, x):
     index = binarySearch(0, len(arr), x)
     if index != -1:
         while index > 0:
           if arr[index] == arr[index-1]:
              index -= 1
           else:
              break
     return index

谢谢!

8 个答案:

答案 0 :(得分:7)

在最坏的情况下,您的方法需要线性时间,即数组中x的计数为O( n )时。

可以通过更改二进制搜索本身来查找数组中的第一个x而不是其中任何一个来获得O(lg n )解决方案:

def binary_search(x, a):
    lo = 0
    hi = len(a)

    while lo < hi:
        mid = (lo + hi) // 2

        if a[mid] < x:
            lo = mid + 1
        elif a[mid] > x:
            hi = mid
        elif mid > 0 and a[mid-1] == x:
            hi = mid
        else:
            return mid

    return -1

答案 1 :(得分:3)

import bisect
l = [1,2,3,4,4,4,4,4,5,5,5,5,5,6,6,7,7,7,8,8]
bisect.bisect_left(l, 4)

编辑: 我只是想念一件事。 bisect会给你一个插入点。因此,如果x不在列表中,您仍将拥有结果索引。所以你需要先检查x是否在列表中:

if x in l:
    ....

但是对于面试问题,他们可能想看看你如何提出算法而不是使用图书馆......

答案 2 :(得分:1)

如果元素是整数 - 或枚举,您可以更快地完成:

请注意,在二进制搜索[算法,而不是python函数]中,如果元素不存在 - 您可以找到比索引大的最小元素。

  1. 首先搜索x - 并获取索引,将其设为i
  2. 接下来,搜索x-1。如果它不在列表中,则进行二进制搜索 可以找到x的第一个索引。
  3. 如果它在列表中,请将索引设为j
    • ji的子列表中进行二元搜索,然后搜索list[k] < list[k+1]
    • 元素
  4. 对于非枚举值,也可以通过在list[k] < list[k+1] and list[k+1] == x时减少范围的相同想法来完成,但我发现首先要了解如何对整数进行更简单的操作,然后将其应用于一般解决方案。

    请注意此解决方案为O(logn) ,而您建议的简单解决方案为O(n) ,列表中包含大量欺骗,因为二进制搜索后的迭代步骤。

答案 3 :(得分:1)

递归版本,如果有人感兴趣的话...

https://github.com/reneargento/algorithms-sedgewick-wayne/blob/master/src/chapter1/section4/Exercise10.java进行重写,这是算法4 的练习。

def binary_search(key, a, low, high):
    if low > high:
        return -1;
    middle = low + (high - low) / 2;
    if a[middle] < key:
        return binary_search(key, a, middle + 1, high)
    elif a[middle] > key:
        return binary_search(key, a, low, middle - 1)
    else:
        if (middle - 1 >= 0) and (a[middle - 1] != key):
            return middle
        else:
            index = binary_search(key, a, 0, middle - 1)
            if(index == -1):
                return middle;
            else:
                return index;

a = [1,2,3,3,3,3,4,5,6,7,7,8,9]

print(binary_search(7, a, 0, len(a)))

递归版本不是总是比非递归版本更直接吗?为什么这看起来很难..?谁能写出更好的递归版本:D?

答案 4 :(得分:0)

如果x不在X f(x) = v,那么答案是微不足道的:二进制搜索以找出它。

如果有一个x使得f(x) = v,那么答案也是微不足道的:二进制搜索以找出它。

如果x有多个f(x) = v,问题就很有趣了。如果存在恒定数量的x,那么在算法上二分搜索是最佳的。只需二元搜索并按顺序检查较低的索引。

但是,如果有很多这些x会怎么样?像这样的顺序搜索显然不是最佳的。事实上,如果有c * |X| x,则会在O(|X|)中运行。

相反可以做的是将lbound初始化为0并进行二元搜索,直到找到i处的元素,每当您向右走时,更新lbound到刚刚使用的中期。然后从[lbound, i - 1]进行二分搜索。这样做直到i == lbound或您没有找到元素。如果前者发生,则所需索引为0。如果发生后者,则所需的索引是先前使用的i。最糟糕的情况是所需的索引是0

有趣的是,我认为这仍然在log(|X|)时间运行。

答案 5 :(得分:0)

deferred detection of equality approach in binary search给出最小的索引,减少相等分支。

def binary_search(low, high, target, array):
    while low < high:
        mid = low + (high - low) / 2
        if a[mid] < target:
            low = mid + 1
        else:
            high = mid

    if (array[low] == target) return low
    else return -1

答案 6 :(得分:-1)

我敢打赌,g.d.d.c的评论是python的最快答案。否则,您的通用算法是正确的,除了在某些情况下您可以击败二进制搜索的O(log n)行为的事实。具体来说,在整数的情况下,您可以获得的最佳最坏情况行为是O(sqrt(log n)): https://stackoverflow.com/questions/4057258/faster-than-binary-search-for-ordered-list

答案 7 :(得分:-1)

修改二进制搜索以首次查找x的任何出现。