找到优于线性时间的三元组,使得A [n-1]> = A [n] <= A [n + 1]

时间:2013-07-12 04:01:15

标签: algorithm language-agnostic

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

3 个答案:

答案 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+1source

答案 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)

执行