是的,它确实可以在O(n) 时间内完成。以下是几种方法。
第一个对于查找所有个候选单元格更有用。对数据进行一次O(n) 传递,为每个单元格设置两个额外的项目,因此O(n) 空间(可以通过以空间换时间来解决大量优化问题)。
每个单元格需要计算的两项是左侧的最大值和右侧的最小值。第一遍为所有单元格设置这些项目,最后一个没有意义(显然是伪代码):
# Set current values.
highLeftVal = cell[0]
lowRightVal = cell[cell.lastIndex]
# For running right and left through array.
rightIdx = cell.lastIndex
for each leftIdx 1 thru cell.lastIndex inclusive:
# Left index done by loop, right one manually.
rightIdx = rightIdx - 1
# Store current values and update.
highLeft[leftIdx] = highLeftVal
if cell[leftIdx] > highLeftVal: highLeftVal = cell[leftIdx]
lowRight[rightIdx] = lowRightVal
if cell[rightIdx] < lowRightVal: lowRightVal = cell[rightIdx]
然后检查每个单元格(第一个和最后一个)以确保值都大于(根据您的问题,此答案假设“更高/更低”是 字面值,不是“大于/小于或等于”)左边最高,小于右边最低:
for each idx 1 thru cell.lastIndex-1 inclusive:
if cell[idx] > highLeft[idx] and cell[idx] < lowRight[idx]
print "Found value ", cell[idx], " at index ", idx
您可以在下面看到初始传递的结果:
highLeft: - 1 3 3 6 6 7 9 9 10 10
cells : 1 3 2 6 5 7 9 8 10 8 11
lowRight: 2 2 5 5 7 8 8 8 8 11 -
^
唯一候选单元格,其中值相对于它上面和下面的两个值进行排序(不包含),是带有^ 标记的7。
现在请记住,这是一个相对容易理解的解决方案,可以找到满足约束条件的多个项。鉴于您只需要 一个 项,就有可能获得更好的性能(尽管仍然是 O(n))。
基本思想是从左到右遍历数组,对于每个单元格,检查左侧是否较低,右侧是否较高。
第一点很容易,因为通过从左到右遍历,您可以记住遇到的最高值。第二点似乎涉及以某种方式展望未来,但您可以使用一个技巧来避免这种“时间体操”。
这个想法是保持当前单元格左侧的最高值和当前答案的索引(最初设置为哨兵值)。
如果当前答案是哨兵值,则选择第一个满足“大于左边所有”的单元格作为可能的答案。
而且,只要情况仍然如此,这就是您选择的单元格。但是,一旦您在其右侧找到小于或等于它的值,它就不再有效,因此您将其丢弃并重新开始搜索。
这个搜索是从当前点开始的,而不是回到起点,因为:
- 当前答案之后直到但不包括此(小于或等于)单元格的所有内容都高于当前答案者,否则您会已经找到一个小于或等于的单元格;和
- 因此,该单元格必须小于或等于该范围内的每个单元格,因为它小于或等于当前答案;因此
-
没有该范围内的单元格有效,它们全部大于或等于这个。
一旦您完成了非结束项目的处理,您的答案将是哨兵或几乎满足约束条件的单元格。
我说“几乎”是因为需要进行一次最终检查以确保最终项目大于它,因为您在遍历过程中没有对该项目执行任何检查。
因此,该野兽的伪代码类似于:
# Store max on left and start with sentinel.
maxToLeft = cell[0]
answer = -1
for checking = 1 to cell.lastIndex-1 inclusive:
switch on answer:
# Save if currently sentinel and item valid.
case -1:
if cell[checking] > maxToLeft:
answer = checking
# Set back to sentinel if saved answer is now invalid.
otherwise:
if cell[answer] >= cell[checking]:
answer = -1
# Ensure we have updated max on left.
if cell[checking] > maxToLeft:
maxToLeft = cell[checking]
# Final check against last cell.
if answer != -1:
if cell[cell.lastIndex] <= cell[answer]:
answer = -1
由于我的伪代码(大量)基于 Python,因此提供一个更具体的代码示例是一件相当简单的事情。首先,“找到每一种可能性”选项:
cell = [1, 3, 2, 6, 5, 7, 9, 8, 10, 8, 11]
highLeft = [0] * len(cell)
lowRight = [0] * len(cell)
highLeftVal = cell[0]
lowRightVal = cell[len(cell)-1]
rightIdx = len(cell) - 1
for leftIdx in range(1, len(cell)):
rightIdx = rightIdx - 1
highLeft[leftIdx] = highLeftVal
if cell[leftIdx] > highLeftVal: highLeftVal = cell[leftIdx]
lowRight[rightIdx] = lowRightVal
if cell[rightIdx] < lowRightVal: lowRightVal = cell[rightIdx]
print(highLeft)
print(cell)
print(lowRight)
for idx in range(1, len(cell) - 1):
if cell[idx] > highLeft[idx] and cell[idx] < lowRight[idx]:
print("Found value", cell[idx], "at index", idx)
还有第二种,效率稍高一些,但只能找到一种可能性:
cell = [1, 3, 2, 6, 5, 7, 9, 8, 10, 8, 11]
maxToLeft = cell[0]
answer = -1
for checking in range(1, len(cell) - 1):
if answer == -1:
if cell[checking] > maxToLeft:
answer = checking
else:
if cell[answer] >=cell[checking]:
answer = -1
if cell[checking] > maxToLeft:
maxToLeft = cell[checking]
if answer != -1:
if cell[len(cell] - 1] <= cell[answer]:
answer = -1
if answer == -1:
print ("Not found")
else:
print("Found value", cell[answer], "at index", answer);
print(highLeft)
print(cell)
print(lowRight)
for idx in range(1, len(cell) - 1):
if cell[idx] > highLeft[idx] and cell[idx] < lowRight[idx]:
print("Found value", cell[idx], "at index", idx)
两者的输出(尽管后一个示例仅显示最后一行)基本上显示了伪代码的意图:
[0, 1, 3, 3, 6, 6, 7, 9, 9, 10, 10]
[1, 3, 2, 6, 5, 7, 9, 8, 10, 8, 11]
[2, 2, 5, 5, 7, 8, 8, 8, 8, 11, 0]
Found value 7 at index 5