鉴于 N 项目的值为x[1], ..., x[n]
且整数 K ,找到一个线性时间算法来排列 N 项目在< em> K 非空组,使得每组中的范围(每组中最小和最大元素值/键之间的差异)最小化,因此范围之和最小。
例如,给定N=4
,K=2
和元素1 1 4 3
,1
和(1,1)
组的最小范围为(4,3)
。
答案 0 :(得分:1)
你可以二元搜索答案 假设最佳答案是 x 。现在,您应该验证我们是否可以将项目分组到 k 组中,其中组项目之间的最大差异最多为 x 。这可以在 O(n) [对数组进行排序]之后完成。遍历已排序的数组并选择连续项目,直到您为该组选择的最小数字与您选择的最大数字之间的差异不超过 x 。之后,您应该初始化一个新组并重复此过程。最后统计你做了多少组。如果组的数量超过 k ,我们可以得出结论,我们无法将 x 组中的项目分组,而 x 就是答案。所以我们应该增加 x 。通过二元搜索 x ,我们可以找到最小的 x 。
整体复杂性为 O(NlogN)。
以下是C ++中的示例实现
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int n = 4, k = 2;
std::vector<int> v = {1, 1, 4, 3};
sort(v.begin(), v.end());
int low = 0, high = *max_element(v.begin(), v.end());
while ( low < high ){
int x = (low+high)/2;
int groups = 0;
int left = 0;
while (left < v.size()){
int right = left;
while( right < v.size() && v[right] - v[left] <= x ){
++right;
}
++groups;
left = right;
}
// printf("x:%d groups:%d\n", x, groups );
if (groups > k)
{
low = x + 1;
} else {
high = x;
}
}
cout << "result is " << low << endl;
}
答案 1 :(得分:0)
好吧,我假设我们希望尽量减少所有群体的差异总和。
让我们对数字进行排序。这是一个最佳答案,其中每个组是排序数组中的连续段(证明:让A1
设a [l],a [l + 1],...,a [r]是一个组。它的费用是a[r] - a[l] = (a[r] - a[r - 1]) + (a[r - 1] - a[r - 2]) + ... + (a[l + 1] - a[l])
。它引导我们获得一个关键洞察力:k
组的差距为k - 1
,答案为a[n - 1] - a[0] - sum of gaps
。因此,我们只需要最大化差距。
以下是最终解决方案:
k - 1
最大差异。这正是群体分裂的地方。k-1
最大的元素(或者如果我们在O(N log N)
时间内没问题,我们可以对它们进行排序)。那就是它。以下是一个例子:
x = [1, 1, 4, 3], k = 2
已排序:[1, 1, 3, 4]
差异:[0, 2, 1]
获取k - 1 = 1
最大差距:它是2.因此,这些群组是[1, 1]
和[3, 4]
。
一个稍微有点做作的人:
x = [8, 2, 0, 3], k = 3
已排序:[0, 2, 3, 8]
差异:[2, 1, 5]
取k - 1 = 2
个最大差距:他们为2和5.因此,这些群组为[0], [2, 3], [8]
,总费用为1。