给定一个N-by-N阵列a N 2 不同的整数,设计一个O(N)算法来找到一个局部最小值:一对索引 i 和 j 这样:
a[i][j] < a[i+1][j]
a[i][j] < a[i-1][j]
a[i][j] < a[i][j+1]
a[i][j] < a[i][j-1]
我在一个在线算法手册Introduction to Programming in Java, chapter 4.2: Sorting and Searching中找到了这个问题。
类似于问题35(同一页):
a[i-1] < a[i] < a[i+1]
)。它有一些基于二进制搜索的解决方案,我无法找到。
答案 0 :(得分:7)
书籍Algorithms by Robert Sedgewick and Kevin Wayne. (See "Creative problems" section, problem 19)的网络版中提到了同样的问题。
作者在that link中提出的问题的提示是:
找到行N / 2中的最小值,检查列中的邻居p和q,如果p或q小于那么在那一半重复。
更好的方法是: 找到行N / 2中的最小值,检查其列中的所有条目,如果我们在列中获得较小的条目,则在较小列条目所属的行中重复。
例如。 对于下面的数组,N = 5:
1 12 3 1 -23
7 9 8 5 6
4 5 6 -1 77
7 0 35 -2 -4
6 83 1 7 -6
第1步:中间一行是[4 5 6 -1 77
]。即。第3行。
第2步:当前行的最小条目为-1
。
步骤3:最小条目的列邻居(即-1
)为5
和-2
。 -2
是最小邻居。它在第4排。
继续执行步骤2-3,直至我们获得local min。
修改强>
例如@anuja的评论中提到的 (主要问题是n-by-n数组。这个输入是3乘4的数组,但我们可以使用它):
1 2 3 4
5 1 6 -1
7 3 4 -2
第1步:中间行为[5 1 6 -1]
。即。第2行。
第2步:当前行的最小条目为-1
。
步骤3:最小条目的列邻居(即-1
)为4
和-2
。
-2
是最小列邻居。它排在第3行。
迭代到步骤2:-2在其行中最小,在其列邻居中最小。所以我们以-2作为局部最小值的输出结束。
答案 1 :(得分:5)
更新:这个答案假设边缘不是局部最小值,因为它们不是由原始问题陈述中的四个比较定义的。在这种情况下,这个答案是正确的(这是不可能的)。如果你重新定义边缘可以是局部最小值的问题,那么每个矩阵至少包含一个局部最小值 - 因此你可以使用分而治之的方法。
如果边缘单元格不能是局部最小值:
如上所述,问题无法解决。 N-by-N阵列仅需要O(N ^ 2)时间来读取元素。由于矩阵中可能存在单个局部最小“隐藏”,因此这是必要的。
如果你想要一个O(N ^ 2)算法,而不是简单地走每个元素并将它与它的4个邻居进行比较需要花费O(N ^ 2)时间。
你要么误解了面试问题(而且还有更多的问题),或者这只是一个简单的编码练习。
<强>证明强>:
1. Construct a NxN matrix such that each cell has the value M[i,j] = N*i + j.
2. Select a random x,y (1 < x < N and 1 < y < N) and assign M[x,y] = -1
该矩阵恰好具有一个局部最小值(M [x,y]),并且其位置独立其他单元格中的值。因此,其他单元提供关于其位置的无信息,因此不可能有任何系统搜索优于预期(N ^ 2/2)单元搜索= O(N)的任何系统^ 2)。
(换句话说,除了最小值的M [x,y] = -1之外,你也可以搜索几乎所有的零矩阵M [i,j] = 0。)
此证明取决于能否在步骤1中构造一个没有局部最小值的矩阵。如果边缘单元可能是局部最小值,则每个矩阵必须有一个,并且此证明不再成立。< / p>
答案 2 :(得分:2)
访问随机单元格。如果它的四个neigbors中的任何一个具有较小的值:去那个单元格。如果没有一个较小的东西,那么你当地的最低限度。如果可以使用具有相等值的单元格,则会更难避免循环。
更新
我们可以选择最小的neigbor而不是访问一个neigbor。
最困难的拓扑似乎是两个“同心”螺旋的情况,其中一个起螺旋堤的作用。在最坏的情况下,这仍然需要大约N / 2步。 (N =细胞数。)