Python中的峰值查找器,O(log n)复杂度

时间:2016-01-29 22:29:05

标签: python

我是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。任何帮助表示赞赏。

5 个答案:

答案 0 :(得分:4)

数据

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提供list comprehensions

>>> [x * 2 for x in range(2, 6)]
[4, 6, 8, 10]

Generator expression以类似的方式工作,但不生成列表但是迭代器,并且可以在不使用大量内存的情况下使用:

>>> sum(x * 2 for x in range(2, 6))
28

答案 1 :(得分:0)

您错过了两个elif个案件的退货声明

答案 2 :(得分:0)

我认为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()

如果你什么都不懂,请问!

答案 3 :(得分:0)

另一种方法 - 只使用一个功能:

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()

答案 4 :(得分:0)

我认为你不能在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)))