设计用于在列表中查找 3 个不同元素的 O(log n) 算法
Design O(log n) algorithm for finding 3 distinct elements in a list
问题是:
Design an O(log n) algorithm whose input is a sorted list A. The algorithm should return true if A contains at least 3 distinct elements. Otherwise, the algorithm should return false.
因为它必须是 O(log n),我尝试使用二进制搜索,这是我写的代码:
def hasThreeDistinctElements(A):
if len(A) < 3:
return False
minInd = 0
maxInd = len(A)-1
midInd = (maxInd+minInd)//2
count = 1
while minInd < maxInd:
if A[minInd] == A[midInd]:
minInd = midInd
if A[maxInd] == A[midInd]:
maxInd = midInd
else:
count += 1
maxInd -= 1
else:
count += 1
minInd += 1
midInd = (maxInd+minInd)//2
return count >= 3
有更好的方法吗?
谢谢
是的,有更好的方法。
由于列表已排序,您可以使用二分查找并稍作自定义修改,如下所示:
list = [1, 1, 1, 2, 2]
uniqueElementSet = set([])
def binary_search(minIndex, maxIndex, n):
if(len(uniqueElementSet)>=3):
return
#Checking the bounds for index:
if(minIndex<0 or minIndex>=n or maxIndex<0 or maxIndex>=n):
return
if(minIndex > maxIndex):
return
if(minIndex == maxIndex):
uniqueElementSet.add(list[minIndex])
return
if(list[minIndex] == list[maxIndex]):
uniqueElementSet.add(list[minIndex])
return
uniqueElementSet.add(list[minIndex])
uniqueElementSet.add(list[maxIndex])
midIndex = (minIndex + maxIndex)//2
binary_search(minIndex+1, midIndex, n)
binary_search(midIndex+1, maxIndex-1, n)
return
binary_search(0, len(list)-1, len(list))
print(True if len(uniqueElementSet)>=3 else False)
因为,我们在递归的每次迭代中将数组分成两部分,它最多需要 log(n) 步来检查它是否包含 3 个唯一元素。
时间复杂度 = O(log(n)).
为了真正成为 O(logN)
,对边界索引 minInd,maxInd
的更新应该永远是
maxInd = midInd [- 1]
minInd = midInd [+ 1]
搜索减半 space。因为有通过你的循环体的路径只做
minInd += 1
maxInd -= 1
分别,我不确定您不能创建您的函数是线性的数据。下面简单一点,保证O(logN)
def x(A):
if len(A) < 3:
return False
minInd, maxInd = 0, len(A)-1
mn, mx = A[minInd], A[maxInd]
while minInd < maxInd:
midInd = (minInd + maxInd) // 2
if mn != A[midInd] != mx:
return True
if A[midInd] == mn:
minInd = midInd + 1 # minInd == midInd might occur
else:
maxInd = midInd # while maxInd != midInd is safe
return False
顺便说一句,如果你会使用标准库,那就很简单了:
from bisect import bisect_right
def x(A):
return A and (i := bisect_right(A, A[0])) < len(A) and A[i] < A[-1]
from bisect import bisect
def hasThreeDistinctElements(A):
return A[:1] < A[-1:] > [A[bisect(A, A[0])]]
第一次安全比较(*) 检查是否有两个不同的值。如果是,我们检查第一个大于 A[0]
的值是否也小于 A[-1]
.
(*):如果 A
为空,则不会崩溃。
或没有 bisect
,二进制搜索 A[1:-1]
中的第三个值。不变量是如果有的话,一定在A[lo : hi+1]
:
def hasThreeDistinctElements(A):
lo, hi = 1, len(A) - 2
while lo <= hi:
mid = (lo + hi) // 2
if A[mid] == A[0]:
lo = mid + 1
elif A[mid] == A[-1]:
hi = mid - 1
else:
return True
return False
问题是:
Design an O(log n) algorithm whose input is a sorted list A. The algorithm should return true if A contains at least 3 distinct elements. Otherwise, the algorithm should return false.
因为它必须是 O(log n),我尝试使用二进制搜索,这是我写的代码:
def hasThreeDistinctElements(A):
if len(A) < 3:
return False
minInd = 0
maxInd = len(A)-1
midInd = (maxInd+minInd)//2
count = 1
while minInd < maxInd:
if A[minInd] == A[midInd]:
minInd = midInd
if A[maxInd] == A[midInd]:
maxInd = midInd
else:
count += 1
maxInd -= 1
else:
count += 1
minInd += 1
midInd = (maxInd+minInd)//2
return count >= 3
有更好的方法吗?
谢谢
是的,有更好的方法。
由于列表已排序,您可以使用二分查找并稍作自定义修改,如下所示:
list = [1, 1, 1, 2, 2]
uniqueElementSet = set([])
def binary_search(minIndex, maxIndex, n):
if(len(uniqueElementSet)>=3):
return
#Checking the bounds for index:
if(minIndex<0 or minIndex>=n or maxIndex<0 or maxIndex>=n):
return
if(minIndex > maxIndex):
return
if(minIndex == maxIndex):
uniqueElementSet.add(list[minIndex])
return
if(list[minIndex] == list[maxIndex]):
uniqueElementSet.add(list[minIndex])
return
uniqueElementSet.add(list[minIndex])
uniqueElementSet.add(list[maxIndex])
midIndex = (minIndex + maxIndex)//2
binary_search(minIndex+1, midIndex, n)
binary_search(midIndex+1, maxIndex-1, n)
return
binary_search(0, len(list)-1, len(list))
print(True if len(uniqueElementSet)>=3 else False)
因为,我们在递归的每次迭代中将数组分成两部分,它最多需要 log(n) 步来检查它是否包含 3 个唯一元素。
时间复杂度 = O(log(n)).
为了真正成为 O(logN)
,对边界索引 minInd,maxInd
的更新应该永远是
maxInd = midInd [- 1]
minInd = midInd [+ 1]
搜索减半 space。因为有通过你的循环体的路径只做
minInd += 1
maxInd -= 1
分别,我不确定您不能创建您的函数是线性的数据。下面简单一点,保证O(logN)
def x(A):
if len(A) < 3:
return False
minInd, maxInd = 0, len(A)-1
mn, mx = A[minInd], A[maxInd]
while minInd < maxInd:
midInd = (minInd + maxInd) // 2
if mn != A[midInd] != mx:
return True
if A[midInd] == mn:
minInd = midInd + 1 # minInd == midInd might occur
else:
maxInd = midInd # while maxInd != midInd is safe
return False
顺便说一句,如果你会使用标准库,那就很简单了:
from bisect import bisect_right
def x(A):
return A and (i := bisect_right(A, A[0])) < len(A) and A[i] < A[-1]
from bisect import bisect
def hasThreeDistinctElements(A):
return A[:1] < A[-1:] > [A[bisect(A, A[0])]]
第一次安全比较(*) 检查是否有两个不同的值。如果是,我们检查第一个大于 A[0]
的值是否也小于 A[-1]
.
(*):如果 A
为空,则不会崩溃。
或没有 bisect
,二进制搜索 A[1:-1]
中的第三个值。不变量是如果有的话,一定在A[lo : hi+1]
:
def hasThreeDistinctElements(A):
lo, hi = 1, len(A) - 2
while lo <= hi:
mid = (lo + hi) // 2
if A[mid] == A[0]:
lo = mid + 1
elif A[mid] == A[-1]:
hi = mid - 1
else:
return True
return False