在A[0] >= A[1]
和A[N-1] >= A[N-2]
的访谈中给出了一系列数字。我被要求找到至少一个三联体,A[n-1] >= A[n] <= A[n+1]
。
我试图在迭代中解决。面试官期望比线性时间解决方案更好。我该如何处理这个问题?
示例:9 8 5 4 3 2 6 7
答案:3 2 6
答案 0 :(得分:9)
我们可以在O(logn)
时间使用divide&amp;征服又名。二分搜索。比线性时间更好。所以我们需要找到A[n-1] >= A[n] <= A[n+1]
的三元组。
首先找到给定数组的中间位置。如果mid小于其左侧且大于右侧。然后回来,这就是你的答案。顺便说一下,这将是递归的基础。如果len(arr) < 3
那么也会回来。另一个基础。
现在出现了递归方案。何时递归,我们需要进一步检查。为此,如果mid大于其左侧的元素,则将数组的左起点视为子问题,并使用此新数组进行递归。也就是说,在这一点上我们将...2
6 ...
,索引n
为6.所以我们向左移动以查看左边的元素2
完成了三重奏。
否则,如果mid大于其右子阵列上的元素,则将数组的mid + 1中间视为子问题并递归。
更多理论:以上内容应足以理解问题但请继续阅读。问题基本上归结为在给定的元素集中找到局部最小值。数组中的数字称为局部最小值,如果它小于左数和右数,则精确归结为A[n-1] >= A[n] <= A[n+1]
。
给定的数组,使其前2个元素正在减少,最后2个元素增加HAS以具有局部最小值。这是为什么?让我们通过否定来证明这一点。如果前两个数字正在减少,并且没有局部最小值,则表示第三个数字小于第二个数字。否则第二个数字将是当地的最小值。遵循相同的逻辑,第四个数字必须小于第三个数字,依此类推。因此,数组中的数字必须按递减顺序排列。这违反了最后两个数字的增加顺序的约束。这通过否定证明需要有一个局部最小值。
上述理论提出了O(n)
线性方法,但我们绝对可以做得更好。但是这个理论肯定会让我们对这个问题有不同的看法。
代码:这是python代码(fyi - 在stackoverflow文本编辑器中徒手输入,可能会错误地写入)。
def local_minima(arr, start, end):
mid = (start+end)/2
if mid-2 < 0 and mid+1 >= len(arr):
return -1;
if arr[mid-2] > arr[mid-1] and arr[mid-1] < arr[mid]: #found it!
return mid-1;
if arr[mid-1] > arr[mid-2]:
return local_minima(arr, start, mid);
else:
return local_minima(arr, mid, end);
请注意,我只返回n
的索引。要打印出三元组,只需对返回的索引执行-1
和+1
。 source
答案 1 :(得分:2)
听起来你问的是这个:
你有一系列数字。它开始减少并继续减少直到元素n
,然后它开始增加直到序列结束。查找n
。
这是线性时间的(非最佳)解决方案:
for (i = 1; i < length(A) - 1; i++)
{
if ((A[i-1] >= A[i]) && (A[i] <= A[i+1]))
return i;
}
要比线性时间更好,您需要使用从序列减少然后增加的事实中获得的信息。
考虑A[i]
和A[i+1]
之间的区别。如果A[i] > A[i+1]
,则为n > i
,因为值仍在减少。如果是A[i] <= A[i+1]
,那么n <= i
,因为值现在正在增加。在这种情况下,您需要检查A[i-1]
和A[i]
之间的区别。
这是日志时间的解决方案:
int boundUpper = length(A) - 1;
int boundLower = 1;
int i = (boundUpper + boundLower) / 2; //initial estimate
while (true)
{
if (A[i] > A[i+1])
boundLower = i + 1;
else if (A[i-1] >= A[i])
return i;
else
boundUpper = i;
i = (boundLower + boundUpper) / 2;
}
如果A
没有满足条件的元素,我会留给您添加必要的错误检查。
答案 2 :(得分:1)
线性你可以通过迭代整个集合来比较它们。
您还可以检查前两个的斜率,然后执行一种二进制切割/按顺序遍历比较对,直到找到相反的斜率之一。我认为这会比n
时间更好地摊销,但不能保证。
编辑:刚刚意识到你的订购意味着什么。二进制斩方法保证在<n
时间内完成此操作,因为保证有一个变化点(假设您的N-1, N-2
是列表的最后两个元素)。
这意味着你只需要找到它/其中一个,在这种情况下,二进制斩将按顺序log(n)