簡體   English   中英

Python中的峰值查找器,復雜度為O(log n)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM