求出非固定长度x的每个子阵列的最小值的最大值,其中1 <= x <= N.

时间:2015-06-21 05:13:32

标签: algorithm dynamic-programming

面试问题:

您在数组中获得 N 个数字。数字的是数组的非空连续段。组的大小是该组中的数字数。

A 成为组中的最小数字。任务是找到每个 x (1&lt; = x &lt; = N),所有组中 A 的最大值尺寸 x

例如,如果 N = 3且数组为[1,2,3],则答案为3(x = 1),2(x = 2),1( x = 3)。

数组可以在数组中重复(例如,对于 N = 7,数组可以是[1,2,3,4,5,4,6]。

为了解释,以下C代码是一个天真的解决方案:

#include <stdio.h>

int main() {
    int a[] = {6,1,3,2,5,4,7};
    size_t N = sizeof a / sizeof *a;

    for (size_t i=0; i<N; ++i) printf("%d ", a[i]); puts("\n");

    size_t group_size, start, i;
    int max, min;
    for (group_size = 1; group_size <= N; ++group_size) {
        max = 0;
        for (start = 0; start <= N - group_size; ++start) {
            min = a[start];
            for (i = start + 1; i < start + group_size; ++i) {
                if (a[i] < min)
                    min = a[i];
            }
            if (min > max)
                max = min;
        }
        printf("%d ", max);
    }

    return 0;
}

输出:

6 1 3 2 5 4 7

7 4 4 2 2 1 1

3 个答案:

答案 0 :(得分:3)

线性时间解决方案的简要示意图:对于每个数组元素,计算该元素最小的最大组的大小。 (通过将两个相等元素中的第一个视为较小来断开关系。)使用简并桶排序以线性时间对元素按其关联大小排序。按大小扫描元素大小,输出到目前为止看到的最大元素(即组大小满足当前阈值的最大元素)。

棘手的一步是计算群组规模。我们保持堆栈并从头开始扫描阵列。对于每个元素,我们弹出大于它的堆栈元素,从而结束它们的组。这是6 1 3 2 5 4 7上的追踪。

stack: (-inf @ -1)  {sentinel}

6 1 3 2 5 4 7 -inf  {sentinel}
^
stack: (-inf @ -1), (6 @ 0)

6 1 3 2 5 4 7 -inf
  ^
pop (6 @ 0): group size of 6 is (1 - (-1)) - 1 = 1
stack: (-inf @ -1), (1 @ 1)

6 1 3 2 5 4 7 -inf
    ^
stack: (-inf @ -1), (1 @ 1), (3 @ 2)

6 1 3 2 5 4 7 -inf
      ^
pop (3 @ 2): group size of 3 is (3 - 1) - 1 = 1
stack: (-inf @ -1), (1 @ 1), (2 @ 3)

6 1 3 2 5 4 7 -inf
        ^
stack: (-inf @ -1), (1 @ 1), (2 @ 3), (5 @ 4)

6 1 3 2 5 4 7 -inf
          ^
pop (5 @ 4): group size of 5 is (5 - 3) - 1 = 1
stack: (-inf @ -1), (1 @ 1), (2 @ 3), (4 @ 5)

6 1 3 2 5 4 7 -inf
            ^
stack: (-inf @ -1), (1 @ 1), (2 @ 3), (4 @ 5), (7 @ 6)

6 1 3 2 5 4 7 -inf
              ^
pop (7 @ 6): group size of 7 is (7 - 5) - 1 = 1
pop (4 @ 5): group size of 4 is (7 - 3) - 1 = 3
pop (2 @ 3): group size of 2 is (7 - 1) - 1 = 5
pop (1 @ 1): group size of 1 is (7 - (-1)) - 1 = 7
stack: (-inf @ -1), (inf @ 7)

答案 1 :(得分:2)

这是一个O(n 2 )解决方案。

将输出数组设置为空,输入数组 a 设置为初始值。

a 非空时:

  • 计算 a 的最大值,以添加到输出数组的开头
  • a 执行收缩操作,其中每个元素a [i]设置为[i]和[i + 1]的最小值,最后一个元素被删除

示例:

output = []
a = [1,2,3,4,5,4,6]
output = [6] // add max of a to start of output array
a = [1,2,3,4,4,4]  // shrink array
output = [4,6] // add max of a to start of output array
a = [1,2,3,4,4]  // shrink array
output = [4,4,6] // add max of a to start of output array
a = [1,2,3,4]  // shrink array
output = [4,4,4,6] // add max of a to start of output array
a = [1,2,3]  // shrink array
output = [3,4,4,4,6] // add max of a to start of output array
a = [1,2]  // shrink array
output = [2,3,4,4,4,6] // add max of a to start of output array
a = [1]  // shrink array
output = [1,2,3,4,4,4,6] // add max of a to start of output array
a = []

在循环的第一次迭代开始时, a 将包含长度为1的所有组中的最小值(仅为初始值)。在第二次迭代开始时,它将包含所有长度为2的组中的最小值,依此类推。

在每次迭代时,元素a [i]到a [j](min(a [i] ... a [j]))的最小值将等于

分(分钟(A [1] ...一个[J-1]),分钟(A [1 + 1] ... A [j]))

因此您可以根据长度为n-1的相邻组计算长度为n的组的最小值。

C代码:

#include <stdio.h>

int main() {
    int a[] = {6,1,3,2,5,4,7};
    size_t i, N = sizeof a / sizeof *a;

    for (i=0; i<N; ++i) printf("%d ", a[i]); puts("\n");

    while(N > 0)
    {
        int max = a[0];
        for(i = 0; i < N - 1; i++)
        {
            if(a[i+1] > max)
               max = a[i+1];
            a[i] = a[i+1] < a[i] ? a[i+1] : a[i];
        }
        printf("%d ", max);
        N--;
    }

    return 0;
}

Demo

答案 2 :(得分:1)

这个问题只是使用花哨的词语。您需要计算的只是反向排序数组中的第(x-1)个最大数。

要看到这一点,假设您有一个表单数组:

A = [12, 14, 26, 50, 43];

如果您对它进行排序,它将变为

A' = [12, 14, 26, 43, 50];

现在,任何需要最大化最小值的子阵列,从最后开始都是长度为x的子阵列。因为对于所有其他可能的子阵列,必须存在小于末端第x个元素的元素,从而减小最小值。

所以为了得到答案,你只需对数组进行反向排序,索引(x - 1)处的元素就是你的答案。

A'' = [50, 43, 26, 14, 12]

可以轻松计算非固定长度x的每个子阵列的最小值的最大值。

修改

例如,参见x从1到3

 Length 1: 50
 Length 2: 43
 Length 3: 26

等等。

<强> EDIT2:

这仅在所有元素都是唯一的情况下才有效。