算法:在圆圈中找到峰值

时间:2012-10-12 20:58:24

标签: algorithm language-agnostic geometry

给定n个整数,以圆圈排列,显示一个可以找到一个峰值的有效算法。峰值是一个不小于其旁边两个数字的数字。

一种方法是遍历所有整数并检查每个整数以查看它是否是峰值。这会产生O(n)时间。似乎应该有某种方式来划分和征服以提高效率。

3 个答案:

答案 0 :(得分:3)

修改

嗯,基思兰德尔证明我错了。 :)

这是Keith用Python实现的解决方案:

def findPeak(aBase):
    N = len(aBase)
    def a(i): return aBase[i % N]

    i = 0
    j = N / 3
    k = (2 * N) / 3
    if a(j) >= a(i) and a(j) >= a(k)
        lo, candidate, hi = i, j, k
    elif a(k) >= a(j) and a(k) >= a(i):
        lo, candidate, hi = j, k, i + N
    else:
        lo, candidate, hi = k, i + N, j + N


    # Loop invariants:
    # a(lo) <= a(candidate)
    # a(hi) <= a(candidate)

    while lo < candidate - 1 or candidate < hi - 1:
        checkRight = True
        if lo < candidate - 1:
            mid = (lo + candidate) / 2
            if a(mid) >= a(candidate):
                hi = candidate
                candidate = mid
                checkRight = False
            else:
                lo = mid
        if checkRight and candidate < hi - 1:
            mid = (candidate + hi) / 2
            if a(mid) >= a(candidate):
                lo = candidate
                candidate = mid
            else:
                hi = mid

    return candidate % N

答案 1 :(得分:2)

这是一个递归O(log n)算法。

假设我们有一个数组,我们知道该段的中间数不小于端点:

A[i] <= A[m] >= A[j]

表示i,j索引为数组,m=(i+j)/2。检查端点和中点之间的元素,即索引x=(3*i+j)/4y=(i+3*j)/4的元素。如果是A[x]>=A[m],则按间隔[i,m]递归。如果是A[y]>=A[m],则按间隔[m,j]递归。否则,在[x,y]区间递归。

在每种情况下,我们都会在上面的区间保持不变量。最终我们得到一个大小为2的区间,这意味着我们找到了一个峰值(将是A[m])。

要将圆转换为数组,请取3个等距样本并定位自己,使最大(或最大的一个)位于区间的中间,其他两个点是终点。运行时间为O(log n),因为每个间隔的大小是前一个间隔的一半。

我已经掩饰了计算索引时如何舍入的问题,但我认为你可以成功地解决这个问题。

答案 2 :(得分:0)

当你说“排成一个圆圈”时,你的意思是像圆形链表或什么?从描述数据集的方式来看,听起来这些整数是完全无序的,并且没有办法查看N个整数并得出关于任何其他整数的任何结论。如果是这种情况,那么蛮力解决方案是唯一可能的解决方案。

编辑:

好吧,如果你不关心最坏情况的时间,那么有一些更有效的方法。天真的方法是查看N i ,N i-1 和N i + 1 以查看Ni是否为峰值,然后重复,但你可以做得更好。

While not done
    If N[i] < N[i+1]
        i++
    Else
        If N[i]>N[i-1]
            Done
        Else
            i+=2

(好吧,不是那么,因为你必须处理N [i] = N [i + 1]的情况。但是非常类似的东西。)

这至少会阻止你将N i 与N i + 1 进行比较,将i加1,然后冗余地比较N i 到N i-1 。不过,这是一个明显的边际收益。你仍然在追逐数字,但是没有办法解决这个问题;盲目地跳跃是没有用的,只要做实际的工作,就没有办法向前看。