问题描述
|
给定每个大小为K的N个数组。.对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。
解决方法
我可以想到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,67
^
11,68
^
10,100 (difference:5)
^
4.继续重复步骤2和3,并存储最小差异。
6,100 (difference:5)
^
6,68
^
10,100 (difference:2)
^
以上将是必需的解决方案。
6,100 (difference:84)
^
6,67
^
11,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指针。
,因此,这里有一个分两步解决此问题的算法:
第一步是将所有数组合并为一个排序后的数组,如下所示:
Combined_val []-包含所有数字
Combined_ind []-保留此数字最初属于哪个数组的索引
此步骤可以在O(K * N * log(N))中轻松完成,但我认为您也可以做得更好(也许不能,您可以查找merge sort的变体,因为它们的步骤与此类似)
现在第二步:
放置代码而不是进行解释比较容易,所以这里是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)。
,这个问题是针对经理
您有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);
}
,我有O(K * N * log(K)),典型的执行要少得多。目前尚无更好的选择。我将首先说明更容易描述的内容(执行时间更长):
对于第一个数组中的每个元素f(循环遍历K个元素)
对于每个数组,从第二个数组开始(循环到N-1个数组)
在数组上执行二进制搜索,然后找到最接近f的元素。这是您的元素(Log(K))
如果为每个阵列添加一个新的楼层索引,则可以优化该算法。执行二进制搜索时,在\'Floor \'到\'K-1 \'之间搜索。
最初,楼层索引为0,对于第一个元素,您将搜索整个数组。一旦找到最接近\'f \'的元素,就用该元素的索引更新地板索引。更糟的情况是相同的(如果第一个数组的最大元素小于任何其他最小值,则Floor可能不会更新),但平均情况会有所改善。
,可接受答案的正确性证明(终端解决方案)
假设该算法找到一个不是最优解(R)的序列A = 。
考虑R中的索引j,以使项目R [j]是R中算法检查的第一个项目,并将其替换为该行中的下一个项目。
令A \'表示该阶段(替换之前)的候选解决方案。由于R [j] = A \'[j]是A \'的最小值,所以它也是R的最小值。
现在,考虑R的最大值R [m]。如果A \'[m] 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) ,这是我如何解决此问题的逻辑,请记住,我们需要从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
第三步:
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
第一个数组:
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