AMAZON面试问题

时间:2011-05-23 07:48:08

标签: amazon

给定N个大小为K的数组... N个数组中的每个K元素都被排序,这些N * K个元素中的每一个都是唯一的。从N个元素的所选子集中选择N个阵列中的每个阵列中的单个元素。减去最小和最大元素。现在,这个 差异应该是最小可能的最小..希望问题很清楚:):)

样品:

N=3, K=3

N=1 : 6, 16, 67
N=2 : 11,17,68
N=3 : 10, 15, 100

如果选择16,17,15,我们得到的最小差异为 17-15 = 2。

7 个答案:

答案 0 :(得分:9)

我能想到O(N * K * N)(经zivo正确指出后编辑,现在不是一个好的解决方案:()解决方案。
1.取N指针最初指向N个数组中的每一个的初始元素。

6, 16, 67
^ 
11,17,68
^
10, 15, 100
^ 

2。找出当前指针O(k)(6和11)中的最高和最低元素,找出它们之间的差异。(5)
3.在该数组中将指向最低元素的指针递增1。

 6, 16, 67
    ^ 
 11,17,68
 ^
 10, 15, 100 (difference:5)
 ^ 

4。继续重复步骤2和3并存储最小差异。

 6, 16, 67
    ^ 
 11,17,68
 ^
 10,15,100 (difference:5)
    ^ 


 6, 16, 67
    ^ 
 11,17,68
    ^
 10,15,100 (difference:2)
    ^ 

以上将是必需的解决方案。

 6, 16, 67
    ^ 
 11,17,68
    ^
 10,15,100 (difference:84)
       ^ 

 6, 16, 67
        ^ 
 11,17,68
    ^
 10,15,100 (difference:83)
       ^ 

依旧......

编辑:

使用堆(如Uri所建议的)可以减少其复杂性。我想到了它但遇到了一个问题:每次从堆中提取一个元素时,必须找到它的数组编号,以便增加该数组的相应指针。 查找数组编号的有效方法肯定可以降低O(K * N log(K * N))的复杂性。一种天真的方式是使用像这样的数据结构

Struct
{
    int element;
    int arraynumer;
}

并重建初始数据,如

 6|0,16|0,67|0

 11|1,17|1,68|1

 10|2,15|2,100|2

最初保留第一列的当前最大值并将指向的元素插入堆中。现在每次提取一个元素时,都可以找到它的数组编号,该数组中的指针递增,新指向的元素可以与当前的max和max指针进行比较。

答案 1 :(得分:3)

所以这是一个算法,分两步解决这个问题:

第一步是将所有数组合并为一个排序数组,如下所示:

combined_val [] - 包含所有数字
combined_ind [] - 保存该数字最初属于哪个数组的索引

这一步可以在O(K * N * log(N))中轻松完成,但我认为你也可以做得更好(也许不是,你可以查找合并排序的变体,因为它们的步骤类似于此)

现在第二步:

只是放置代码而不是解释更容易,所以这里是pseduocode:


int count[N] = { 0 }
int head = 0;
int diffcnt = 0;
// mindiff is initialized to overall maximum value - overall minimum value
int mindiff = combined_val[N * K - 1] - combined_val[0];
for (int i = 0; i < N * K; i++) 
{
  count[combined_ind[i]]++;

  if (count[combined_ind[i]] == 1) {
    // diffcnt counts how many arrays have at least one element between
    // indexes of "head" and "i". Once diffcnt reaches N it will stay N and
    // not increase anymore
    diffcnt++;
  } else {
    while (count[combined_ind[head]] > 1) {
      // We try to move head index as forward as possible while keeping diffcnt constant.
      // i.e. if count[combined_ind[head]] is 1, then if we would move head forward
      // diffcnt would decrease, that is something we dont want to do.
      count[combined_ind[head]]--;
      head++;
    }
  }

  if (diffcnt == N) {
    // i.e. we got at least one element from all arrays
    if (combined_val[i] - combined_val[head] < mindiff) {
      mindiff = combined_val[i] - combined_val[head];
      // if you want to save actual numbers too, you can save this (i.e. i and head
      // and then extract data from that)
    }
  }
}

结果是记在心里。

第二步的运行时间是O(N * K)。这是因为“head”索引最多只能移动N * K倍。所以内环不会使这个二次方,它仍然是线性的。

所以总算法运行时间是O(N * K * log(N)),但这是因为合并步骤,如果你能想出更好的合并步骤,你可以把它降到O(N * K) )。

答案 2 :(得分:3)

此问题适用于经理

你有3个开发人员(N1),3个测试人员(N2)和3个DBA(N3) 选择可以成功运行项目的不太分散的团队。

int[n] result;// where result[i] keeps the element from bucket N_i

int[n] latest;//where latest[i] keeps the latest element visited from bucket N_i

Iterate elements in (N_1 + N_2 + N_3) in sorted order
{
    Keep track of latest element visited from each bucket N_i by updating 'latest' array;

    if boundary(latest) < boundary(result)
    {
       result = latest;
    }
}

int boundary(int[] array)
{
   return Max(array) - Min(array);
}

答案 3 :(得分:1)

我有O(K * N * log(K)),典型的执行要少得多。目前想不出更好的事情。我先解释一下更容易描述(执行时间稍长):

  1. 对于第一个数组中的每个元素f(循环通过K个元素)
  2. 对于每个阵列,从第二个阵列开始(循环到N-1阵列)
  3. 对数组进行二进制搜索,找到最接近f的元素。这是你的元素(Log(K))
  4. 可以优化此算法,如果对于每个阵列,则添加新的楼层索引。执行二进制搜索时,在“Floor”和“K-1”之间搜索。 最初Floor索引为0,对于第一个元素,您搜索整个数组。找到最接近'f'的元素后,使用该元素的索引更新Floor Index。更糟糕的情况是相同的(如果第一个数组的最大元素小于任何其他最小值,则Floor可能不会更新),但平均情况会有所改善。

答案 4 :(得分:1)

接受答案的正确性证明(终端解决方案)

假设算法找到一系列A =&lt; A [1],A [2],...,A [N]&gt;这不是最佳解决方案(R)。

考虑R中的索引j,使得项R [j]是算法检查的R中的第一项,并将其替换为其行中的下一项。

让A'表示该阶段(替换之前)的候选解决方案。由于R [j] = A'[j]是A'的最小值,因此它也是R的最小值。 现在,考虑R的最大值R [m]。如果A'[m]

答案 5 :(得分:0)

对于第一个数组中的每个元素

    choose the element in 2nd array that is closest to the element in 1st array
    current_array = 2;
    do
    {
        choose the element in current_array+1 that is closest to the element in current_array
        current_array++;
    } while(current_array < n);

复杂度:O(k ^ 2 * n)

答案 6 :(得分:0)

这是关于如何解决这个问题的逻辑,记住我们需要从每个N个数组中选择一个元素(以计算最小的数量)

// if we take the above values as an example!
// then the idea would be to sort all three arrays while keeping another
// array to keep the reference to their sets (1 or 2 or 3, could be 
// extended to n sets)      
1   3   2   3   1   2   1   2   3    // this is the array that holds the set index
6   10  11  15  16  17  67  68  100  // this is the sorted combined array.
           |           |   
    5            2          33       // this is the computed least minimum,
                                     // the rule is to make sure the indexes of the values 
                                     // we are comparing are different (to make sure we are 
// comparing elements from different sets), then for example
// the first element of that example is index:1|value:6 we hold 
// that value 6 (that is the value we will be using to compute the least minimum, 
// then we go to the edge of the comparison which would be the second different index, 
// we skip index:3|value:10 (we remove it from the array) we compare index:2|value:11 
// to index:1|value:6 we obtain 5 which would go to a variable named leastMinimum = 5, 
// now we remove the indexes and values we already used,
// and redo the same steps.

第1步

1   3   2   3   1   2   1   2   3
6   10  11  15  16  17  67  68  100
           |   
5            
leastMinumum = 5

第2步:

3   1   2   1   2   3
15  16  17  67  68  100
           |   
 2          
leastMinimum = min(2, leastMinumum) // which is equal 2

第3步:

1   2   3
67  68  100

    33
leastMinimum = min(33, leastMinumum) // which is equal to old leastMinumum which is 2

现在:我们假设我们有来自同一阵列的元素彼此非常接近(这次k = 2,这意味着我们只有3组有两个值):

// After sorting the n arrays we will have the below indexes array and values array
1   1   2   3   2   3
6   7   8   12  15  16
*       *   *

* we skip second index of 1|7 and we take the least minimum of 1|6 and 3|12 (index:2|value:8 will be removed as it is not at the edges, we pick the minimum and maximum of the unique index subset of n elements)
1   3         
6   12
 =6
* second step we remove the values we already used, so the array become like below:

1   2   3
7   15  16
*   *   * 
7 - 16
= 9

注意: 消耗更多内存的另一种方法是创建N个子数组,我们将从中比较最大值 - 最小值

因此,从以下排序值数组及其对应的索引数组中,我们提取了另外三个子数组:

1   3   2   3   1   2   1   2   3
6   10  11  15  16  17  67  68  100

First Array:

1   3   2 
6   10  11

11-6 = 5

第二阵列:

3   1   2
15  15  17

17-15 = 2

第三阵列:

1   2   3
67  68  100

100 - 67 = 33