我在微软采访中得到了这个问题:给定一个未排序的数组,找到数组中两个元素之间的最大减法是这样的:
(Index1, Index2) = arr[Index2] - arr[Index1]. Index1<Index2.
示例:
given the array: [1, 5, 3, 2, 7, 9, 4, 3] -> Output: (1,9)=8.
given the array: [4, 9, 2, 3, 6, 3, 8, 1] -> Output: (2,8)=6.
天真的解决方案在O(n ^ 2)次上工作:用所有其他索引扫描第一个减法索引并保存最大值,继续下一个索引,依此类推。
有没有办法优化这个?
答案 0 :(得分:3)
写下来时非常简单。重新解决问题,您希望找到每个元素右侧的最大元素。现在给出第一个例子,这是:
[1, 5, 3, 2, 7, 9, 4, 3]
=>
[9, 9, 9, 9, 9, 4, 3]
现在,请注意,maximums数组只是右边的累积最大值。有了这个属性,很容易构造O(n)
时间算法。
在python中实现:
def find_max(xs):
ys = []
cur_max = float('-inf')
for x in reversed(xs):
cur_max = max(x, cur_max)
ys.append(cur_max)
ys = ys[::-1][1:]
return max(y - x for x, y in zip(xs, ys))
我们也可以懒惰地构造最大数组,这样做会给我们O(1)
内存,这是最好的:
def find_max(xs):
cur_max = float('-inf')
cum_max = xs[-1]
for i in range(len(xs) - 2, -1, -1):
cur_max = max(cur_max, cum_max - xs[i])
cum_max = max(cum_max, xs[i])
return cur_max
答案 1 :(得分:1)
我认为这是正确的并且O(nlogn):在中间分割并从右边选择最大值,从左边开始选择最小值。另外两个季度分开,如果其中一个给出更大的结果继续递归该分支。
第二个例子:
4, 9, 2, 3| 6, 3, 8, 1 -> 2 and 8
4, 9| 2, 3, 6, 3, 8, 1 -> 4 and 8
4, 9, 2, 3, 6, 3| 8, 1 -> 2 and 8
所以正在进行正确的分裂:
4, 9, 2, 3, 6, 3, 8| 1 -> 2 and 1
选择2
和8
选项。它也适用于第一个例子。