[英]Peak finder in Python in O(log n) complexity
我是Python的新手,因此提出了問題。 我正在嘗試解決一個標准的面試問題,即在陣列中找到一個高峰。 峰值定義為大於其左右鄰居的數字。 我試圖找到最大的這樣的高峰。
這是我的代碼:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peak(arr))
def find_peak(arr):
return _find_peak(arr, 0, len(arr))
def _find_peak(arr, start, stop):
mid = (start + stop) // 2
if arr[mid] > arr[mid - 1] and arr[mid] > arr[mid + 1]:
return arr[mid]
elif arr[mid] < arr[mid - 1]:
_find_peak(arr, 0, mid - 1)
elif arr[mid] < arr[mid + 1]:
_find_peak(arr, mid + 1, stop)
if __name__ == '__main__':
main()
該程序的輸出為None
,其中預期輸出為24
。 任何幫助表示贊賞。
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
一行就足夠了:
max_peak = max(x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3)
當您不熟悉Python時,可能更容易理解:
peak = float('-inf')
for x1, x2, x3 in zip(arr, arr[1:], arr[2:]):
if x1 < x2 > x3:
peak = max(peak, x2)
print(peak)
輸出:
24
您還可以使用單線獲取所有峰:
>>> [x2 for x1, x2, x3 in zip(arr, arr[1:], arr[2:]) if x1 < x2 > x3]
[13, 24]
並使用max()
獲得最大的結果。
讓我們看一下解決方案的一些組件。 每個人都應該在這里使用Python 3。 ;)
您可以切片列表。
>>> arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
這將為您提供除第一個元素以外的所有列表:
>>> arr[1:]
[12, 13, 8, 2, 16, 24, 11, 5, 1]
這里從元素三開始:
>>> arr[2:]
[13, 8, 2, 16, 24, 11, 5, 1]
zip()函數將多個序列壓縮在一起。 為了可視化發生的情況,您可以將zip對象轉換為列表:
>>> list(zip(arr, arr[1:], arr[2:]))
[(7, 12, 13),
(12, 13, 8),
(13, 8, 2),
(8, 2, 16),
(2, 16, 24),
(16, 24, 11),
(24, 11, 5),
(11, 5, 1)]
Python支持元組拆包。 這允許為元組的所有成員分配單獨的名稱:
>>> x1, x2, x3 = (7, 12, 13)
>>> x1
7
>>> x2
12
>>> x3
13
另一個不錯的功能是比較兩個以上的對象:
>>> 10 < 12 > 8
True
這等效於:
>>> (10 < 12) and (12 > 8)
True
Python提供列表理解 :
>>> [x * 2 for x in range(2, 6)]
[4, 6, 8, 10]
生成器表達式的工作方式類似,但是不生成列表,而是迭代器,並且無需使用大量內存就可以使用它:
>>> sum(x * 2 for x in range(2, 6))
28
您缺少兩個elif
案例的退貨聲明
我認為13也是一個峰值(大於12和8)。
試試這種方法:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
return list(_search(arr))
def _search(arr):
last = len(arr) - 1
for i, e in enumerate(arr):
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e)):
yield e
if __name__ == '__main__':
main()
如果您什么都不懂,請詢問!
另一種方法–僅使用一個功能:
def main():
arr = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1]
print(find_peaks(arr))
def find_peaks(arr):
last = len(arr) - 1
return [
e for i, e in enumerate(arr)
if not any((i > 0 and arr[i-1] > e, i < last and arr[i+1] > e))
]
if __name__ == '__main__':
main()
我認為您無法在O(log N)時間中找到一個峰值,因為根據定義,這些項目無法按順序排列,並且在給定其他項目的情況下,無法預測列表中任何項目的峰值,除了比較項目N和項目N + 1大概是自反的-它告訴您N或N + 1可能是一個峰值。 這樣您就可以進行N / 2次比較,然后必須再進行N / 2次比較才能檢查峰的另一側。
這是一個local_maxima(iterable)
函數,您可以將其與max()
一起使用以查找峰。 如果開始/結束元素大於一個相鄰元素,則將其視為峰值。
data = [7, 12, 13, 8, 2, 16, 24, 11, 5, 1, None, 2, None, 3, 4, None, 5, 1, None]
firstpeak = [12, 7, 9, 8]
lastpeak = [1, 2, 3, 4]
def local_maxima(it):
"""Find local maxima in iterable _it_. Compares with None using
`is (not) None`, and using operator `<`."""
peaking = False
last = None
for item in it:
# Deal with last item peaking
if peaking and (item is None or item < last):
yield last
peaking = False
elif item is None:
peaking = False
elif last is None or last < item:
peaking = True
else:
peaking = False
last = item
if peaking:
yield last
print([x for x in local_maxima(data)])
print("Highest:", max(local_maxima(data)))
print([x for x in local_maxima(firstpeak)])
print("Highest:", max(local_maxima(firstpeak)))
print([x for x in local_maxima(lastpeak)])
print("Highest:", max(local_maxima(lastpeak)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.