子段中最大值的最小值...复杂度为 O(n)

发布于 2024-12-21 08:28:14 字数 866 浏览 2 评论 0原文

几天前我面试了亚马逊。我无法对他们提出的问题做出令他们满意的回答。我曾试图在面试后得到答案,但到目前为止还没有成功。问题是:

你有一个大小为 n 的整数数组。您将获得参数k,其中k k k。 n。对于数组中大小为 k 的连续元素的每个段,您需要计算最大值。您只需要返回这些最大值中的最小值。

例如,给定 1 2 3 1 1 2 1 1 1k = 3,答案是 1
这些段将是 1 2 32 3 13 1 11 1 21 2 12 1 11 1 1
每个段中的最大值为 33322 >、21
这些值的最小值为 1,因此答案为 1

我想出的最佳答案是复杂度 O(n log k)。我所做的是使用前 k 个元素创建一棵二叉搜索树,获取树中的最大值并将其保存在变量 minOfMax 中,然后在 a 处循环一个元素时间与数组中的剩余元素,从二叉搜索树中删除前一段的第一个元素,插入树中新段的最后一个元素,获取树中的最大元素并将其与 minOfMax 进行比较 留在 minOfMax 中两者的最小值。

理想的答案需要具有复杂度 O(n)。 谢谢。

I interviewed with Amazon a few days ago. I could not answer one of the questions the asked me to their satisfaction. I have tried to get the answer after the interview but I have not been successful so far. Here is the question:

You have an array of integers of size n. You are given parameter k where k < n. For each segment of consecutive elements of size k in the array you need to calculate the maximum value. You only need to return the minimum value of these maximum values.

For instance given 1 2 3 1 1 2 1 1 1 and k = 3 the answer is 1.
The segments would be 1 2 3, 2 3 1, 3 1 1, 1 1 2, 1 2 1, 2 1 1, 1 1 1.
The maximum values in each segment are 3, 3, 3, 2, 2, 2, 1.
The minimum of these values are 1 thus the answer is 1.

The best answer I came up with is of complexity O(n log k). What I do is to create a binary search tree with the first k elements, get the maximum value in the tree and save it in variable minOfMax, then loop one element at a time with the remaining elements in the array, remove the first element in the previous segment from the binary search tree, insert the last element of the new segment in the tree, get the maximum element in the tree and compare it with minOfMax leaving in minOfMax the min value of the two.

The ideal answer needs to be of complexity O(n).
Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

酷炫老祖宗 2024-12-28 08:28:14

There is a very clever way to do this that's related to this earlier question. The idea is that it's possible to build a queue data structure that supports enqueue, dequeue, and find-max in amortized O(1) time (there are many ways to do this; two are explained in the original question). Once you have this data structure, begin by adding the first k elements from the array into the queue in O(k) time. Since the queue supports O(1) find-max, you can find the maximum of these k elements in O(1) time. Then, continuously dequeue an element from the queue and enqueue (in O(1) time) the next array element. You can then query in O(1) what the maximum of each of these k-element subarrays are. If you track the minimum of these values that you see over the course of the array, then you have an O(n)-time, O(k)-space algorithm for finding the minimum maximum of the k-element subarrays.

Hope this helps!

往日 2024-12-28 08:28:14

@templatetypedef 的答案有效,但我认为我有更直接的方法。

首先计算以下(闭合)间隔的最大值:

[k-1, k-1]
[k-2, k-1]
[k-3, k-1]
...
[0, k-1]

请注意,每个间隔都可以在恒定时间内从前一个间隔计算出来。

接下来,计算这些间隔的最大值:

[k, k]
[k, k+1]
[k, k+2]
...
[k, 2k-1]

现在这些间隔:

[2k-1, 2k-1]
[2k-2, 2k-1]
[2k-3, 2k-1]
...
[k+1, 2k-1]

接下来计算从 2k 到 3k-1(“向前间隔”)的间隔,然后从 3k-1 向下到 2k+1(“向后间隔”)。依此类推,直到到达数组的末尾。

把所有这些都放到一张大桌子上。请注意,该表中的每个条目都需要恒定的时间来计算。观察表中最多有 2*n 个间隔(因为每个元素在“向前间隔”的右侧出现一次,在“向后间隔”的左侧出现一次)。

现在,如果 [a,b] 是宽度为 k 的任意区间,则它必须恰好包含 0、k、2k、... 之一,

假设它包含 m*k。

观察区间 [a, m*k-1] 和 [m*k ,b] 都在我们表中的某个位置。因此,我们可以简单地查找每个值的最大值,这两个值的最大值就是区间 [a,b] 的最大值。

因此,对于任何宽度为 k 的间隔,我们可以使用我们的表在常数时间内获得其最大值。我们可以在 O(n) 时间内生成表。结果如下。

@templatetypedef's answer works, but I think I have a more direct approach.

Start by computing the max for the following (closed) intervals:

[k-1, k-1]
[k-2, k-1]
[k-3, k-1]
...
[0, k-1]

Note that each of these can be computed in constant time from the preceeding one.

Next, compute the max for these intervals:

[k, k]
[k, k+1]
[k, k+2]
...
[k, 2k-1]

Now these intervals:

[2k-1, 2k-1]
[2k-2, 2k-1]
[2k-3, 2k-1]
...
[k+1, 2k-1]

Next you do the intervals from 2k to 3k-1 ("forwards intervals"), then from 3k-1 down to 2k+1 ("backwards intervals"). And so on until you reach the end of the array.

Put all of these into a big table. Note that each entry in this table took constant time to compute. Observe that there are at most 2*n intervals in the table (because each element appears once on the right side of a "forwards interval" and once on the left side of a "backwards interval").

Now, if [a,b] is any interval of width k, it must contain exactly one of 0, k, 2k, ...

Say it contains m*k.

Observe that the intervals [a, m*k-1] and [m*k ,b] are both somewhere in our table. So we can simply look up the max for each, and the max of those two values is the max of the interval [a,b].

So for any interval of width k, we can use our table to get its maximum in constant time. We can generate the table in O(n) time. Result follows.

半边脸i 2024-12-28 08:28:14

我在 C# 中实现(并评论)了 templatetypedef 的答案。

n 是数组长度,k 是窗口大小。

    public static void printKMax(int[] arr, int n, int k)
    {
        Deque<int> qi = new Deque<int>(); 
        int i;

        for (i=0 ; i < k ; i++) // The first window of the array
        {
            while ((qi.Count > 0) && (arr[i] >= arr[qi.PeekBack()]))
            {
                qi.PopBack();
            }
            qi.PushBack(i);
        }

        for(i=k ; i < n ; ++i)
        {
            Console.WriteLine(arr[qi.PeekFront()]); // the first item is the largest element in previous window. The second item is its index.

            while (qi.Count > 0 && qi.PeekFront() <= i - k) 
            {
                qi.PopFront(); //When it's out of its window k 
            }
            while (qi.Count>0 && arr[i] >= arr[qi.PeekBack()]) 
            {
                qi.PopBack();
            }
            qi.PushBack(i);
        }
        Console.WriteLine(arr[qi.PeekFront()]);
    }

I implemented (and commented) templatetypedef's answer in C#.

n is array length, k is window size.

    public static void printKMax(int[] arr, int n, int k)
    {
        Deque<int> qi = new Deque<int>(); 
        int i;

        for (i=0 ; i < k ; i++) // The first window of the array
        {
            while ((qi.Count > 0) && (arr[i] >= arr[qi.PeekBack()]))
            {
                qi.PopBack();
            }
            qi.PushBack(i);
        }

        for(i=k ; i < n ; ++i)
        {
            Console.WriteLine(arr[qi.PeekFront()]); // the first item is the largest element in previous window. The second item is its index.

            while (qi.Count > 0 && qi.PeekFront() <= i - k) 
            {
                qi.PopFront(); //When it's out of its window k 
            }
            while (qi.Count>0 && arr[i] >= arr[qi.PeekBack()]) 
            {
                qi.PopBack();
            }
            qi.PushBack(i);
        }
        Console.WriteLine(arr[qi.PeekFront()]);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文