给定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。
答案 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)),典型的执行要少得多。目前想不出更好的事情。我先解释一下更容易描述(执行时间稍长):
可以优化此算法,如果对于每个阵列,则添加新的楼层索引。执行二进制搜索时,在“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