给定n
个整数,以圆圈排列,显示一个可以找到一个峰值的有效算法。峰值是一个不小于其旁边两个数字的数字。
一种方法是遍历所有整数并检查每个整数以查看它是否是峰值。这会产生O(n)
时间。似乎应该有某种方式来划分和征服以提高效率。
答案 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)/4
和y=(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 。不过,这是一个明显的边际收益。你仍然在追逐数字,但是没有办法解决这个问题;盲目地跳跃是没有用的,只要做实际的工作,就没有办法向前看。