给定一个排列在圆形上的包含 n
个整数的序列,设计一种高效的算法来找到其中的一个峰值。峰值是指该数字不小于相邻两个数字。
一种方法是遍历所有整数,并检查每个整数是否为峰值。这样的时间复杂度为 O(n)
。但似乎应该有一些分治的方法可以更加高效。
给定一个排列在圆形上的包含 n
个整数的序列,设计一种高效的算法来找到其中的一个峰值。峰值是指该数字不小于相邻两个数字。
一种方法是遍历所有整数,并检查每个整数是否为峰值。这样的时间复杂度为 O(n)
。但似乎应该有一些分治的方法可以更加高效。
好的,Keith Randall证明了我错了。 :)
这是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
O(log n)
算法。A[i] <= A[m] >= A[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]
上进行递归。A[m]
)。O(log n)
,因为每个区间的大小是前一个区间的一半。当你说“按照圆形排列”时,你是指像循环链表一样吗?从你描述数据集的方式来看,这些整数是完全无序的,没有办法查看N个整数并对其他任何一个得出任何结论。如果是这种情况,那么暴力解决方案是唯一可能的。
编辑:
嗯,如果你不关心最坏情况下的时间,还有更高效的方法可以做到这一点。天真的方法是查看Ni、Ni-1和Ni+1是否为峰值,然后重复此过程,但你可以做得更好。
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 进行比较,将1添加到i,然后冗余地将N i 与N i-1 进行比较。虽然这只是微不足道的收益,但仍然在数字中前进,但没有办法绕过它;盲目跳跃是没有帮助的,而且没有办法提前查看,而不需要花费实际工作所需的时间。
A[1..n]
。 - Paul S.