Python 在预排序数组中查找给定值的最低索引
嘿,我在一次采访中遇到了这个问题,我想知道解决这个问题的最好方法是什么。假设你得到一个已经排序的数组,你想找到某个值x的最低索引 这里是我提出的python/伪代码,我只是想知道是否有更好的方法Python 在预排序数组中查找给定值的最低索引,python,algorithm,Python,Algorithm,嘿,我在一次采访中遇到了这个问题,我想知道解决这个问题的最好方法是什么。假设你得到一个已经排序的数组,你想找到某个值x的最低索引 这里是我提出的python/伪代码,我只是想知道是否有更好的方法 def findLowestIndex(arr, x): index = binarySearch(0, len(arr), x) if index != -1: while index > 0: if arr[index] == arr
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
谢谢
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)
编辑:
我只是错过了一件事。对分将为您提供一个插入点。因此,如果x不在列表中,您仍将有一个结果索引。因此,您需要首先检查x是否在列表中:
if x in l:
....
但对于面试问题,他们可能想看看你是如何提出算法而不是使用库的…我敢打赌,g.d.d.c的评论是python最快的答案。否则,您的通用算法是正确的,除了在某些情况下您可以击败二进制搜索的O(logn)行为。具体来说,对于整数,您可以得到的最佳最坏情况行为是O(sqrt(logn)):
在最坏的情况下,您的方法需要线性时间,即数组中
x
s的计数为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
def二进制搜索(x,a):
lo=0
hi=len(a)
当lox:
高=中
elif mid>0且a[mid-1]==x:
高=中
其他:
中途返回
返回-1
如果元素是整数或枚举的,则可以加快速度:
请注意,在二进制搜索[算法,而不是python函数]中,如果元素不存在,您可以找到比索引大的最小元素
x
-并获取索引,让它成为i
x-1
。如果不在列表中,则二进制搜索
如果x
,可以找到第一个索引j
:
- 在子列表上执行从
到j
的二进制搜索,并搜索i
list[k]
列出[k]
,但我发现首先理解如何对整数进行此操作,然后将其应用于一般解更简单
请注意,此解决方案是
O(logn)
,而您建议的琐碎解决方案是O(n)
,在列表中有许多重复项,这是因为二进制搜索后的迭代步骤。如果x
不在x
中,则f(x)=v
那么答案就很简单了:通过二进制搜索找到答案
如果有一个x
使得f(x)=v
那么答案也很简单:用二进制搜索来找到它
只有当存在多个x
,使得f(x)=v
时,问题才有趣。如果存在恒定数量的x
,则从算法上讲,二进制搜索是最优的。只需按顺序进行二进制搜索并检查较低的索引
但是,如果有很多这样的x
?这样的顺序搜索显然不是最优的。事实上,如果存在c*| X |
X
,那么这将在O(| X |)
中运行
相反,可以做的是将lbound
初始化为0
并进行二进制搜索,直到在i
找到元素,每次向右移动时,将lbound
更新到刚才使用的mid。然后从[lbound,i-1]
进行二进制搜索。直到i==lbound
或找不到元素为止。如果出现前者,则所需索引为0
。如果出现后一种情况,则所需索引为先前使用的i
。最坏的情况是所需索引为0
有趣的是,这仍然在
日志(|X |)中运行。修改二进制搜索以第一次找到任何出现的X。给出了最小的索引,减少了相等分支
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
def二进制搜索(低、高、目标、阵列):
低<高:
中=低+(高-低)/2
如果[mid]<目标:
低=中+1
其他:
高=中
如果(数组[低]==目标)返回低
否则返回-1
递归版本,如果有人感兴趣
重写,一个来自算法4的练习
def二进制搜索(键、a、低、高):
如果低>高:
返回-1;
中=低+(高-低)/2;
如果是[中间]<键:
返回二进制搜索(键,a,中+1,高)
elif a[middle]>键:
返回二进制搜索(键、a、低、中-1)
其他:
如果(中间-1>=0)和(中间-1]!=键):
返回中间
其他:
索引=二进制搜索(键,a,0,中间-1)
如果(索引==-1):
返回中间;
其他:
收益指数;
a=[1,2,3,3,3,3,4,5,6,7,7,8,9]
打印(二进制搜索(7,a,0,len(a)))
递归版本不总是比非递归版本更直观吗?为什么这看起来更难。。?有谁能编写一个更好的递归版本:D吗?我想他们要求您不要使用[1,2,3]。索引(2)
?否则,任何方法都会显得有些过分。我有两种不同的语言,我可以用它们来编写它,所以我想要的不仅仅是python。我可以想象array.index(x)函数是高度优化的,但是该函数不能对数组的状态做出任何假设(我知道它已经被优化了)
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)))