Algorithm 将整数数组划分为K个组,使每个组的范围最小
所以,更正式地说,我得到了N个数字,需要把它们分成K个组,这些组中没有一个是空的。每个组的范围总和必须最小。例如: N=4,K=2,输入为{5,3,1,1} 一种可能的解决方案是{5,3},{1,1}。范围之和为2((5-3)+(1-1)) 另一种方法是{1,1,3}{5},它也是2((3-1)+(单个数字的范围是0)) 范围始终是组中最大数字与组中最小数字之间的差值 当我在互联网上搜索时,很明显我需要使用动态规划,但我得到的只是K=2的解决方案 有人能帮忙吗Algorithm 将整数数组划分为K个组,使每个组的范围最小,algorithm,partitioning,Algorithm,Partitioning,所以,更正式地说,我得到了N个数字,需要把它们分成K个组,这些组中没有一个是空的。每个组的范围总和必须最小。例如: N=4,K=2,输入为{5,3,1,1} 一种可能的解决方案是{5,3},{1,1}。范围之和为2((5-3)+(1-1)) 另一种方法是{1,1,3}{5},它也是2((3-1)+(单个数字的范围是0)) 范围始终是组中最大数字与组中最小数字之间的差值 当我在互联网上搜索时,很明显我需要使用动态规划,但我得到的只是K=2的解决方案 有人能帮忙吗 对数组进行排序 设am为数组的第m
使用动态编程,您为k=2找到了一个解决方案。现在考虑如何将其扩展到k=3
假设f2(n)返回k=2和前n个数字的最优解,f3(n)=f2(n-m)+err(n-m,n)。这是扩展它的一种方法。假设数据已排序,则可以在线性时间内执行此操作 您可以在
min\u value
和max\u value
之间的轴上查看数据。简单地说,智能解决方案不使用非连续组,因此任何智能解决方案都可以表示为轴上的一组K
段,每个段[x1,x2]
表示数据中x1
和x2
之间的所有数字
解决方案的总成本是所有段长度的总和,也是max\u value-min\u value-(所有段之间的空间)
。段之间的空间本身由K-1
空段组成,即没有输入数字,即两个连续输入数字之间的段。您需要的是使K-1
这些段的长度之和最大化
因此,您所要做的就是(简单版本):
- 如有必要,对输入进行排序
- 计算所有i的B[i]=A[i+1]-A[i](A是排序后的输入数组)
- 检索B的K-1最大值(仍然是线性时间,实际上可以与上一步同时进行)
- 这些是您的组的边界,因此您可以再次迭代以创建组本身(现在您有了边界)(此步骤也可以与前面的步骤一起完成)
如前所述,额外的内存复杂度很容易达到O(K),因此在这个问题中,我们希望最小化组的范围 假设我们有array
A={1,3,5,7,5,2}
每个数组中的最大范围为max[a]-min[a]
,最小范围为0
我们可以使用二进制搜索的一种变体来寻找最小范围,这个答案是有限制的,即组必须包含连续数
对于二进制搜索,我们需要选择由数组的最小和最大范围给出的边界
这个psuedo/java代码看起来像这样
main(){
int upper = max(A)-min(A);
int lower = 0;
while (true) {
int mid = upper-lower;
int blocks = calculateBlockCount(A, mid);
if (blocks < K) {
upper = mid - 1;
}
else if (blocks > K) {
lower = mid + 1;
}
else {
return upper;
break;
}
}
}
private static int calculateBlockCount(int[] array, int range) {
int count = 0;
int[] dumie_array;
int dumie_array[].add[array[0]];
for (int i = 0; i < array.length; i++) {
int dumie_array[].add[array[i]]
if (Func_range(dumie_array) > range) {
count++;
dumie_array = array[i];
}
else {
dumie_array.add(array[i]);
}
}
return count;
}
private static int Func_range(int[] input) {
int range = 0;
range= max(input)-min(input)
return sum;
}
main(){
int上限=最大值(A)-最小值(A);
整数下限=0;
while(true){
int mid=上下;
int blocks=calculateBlockCount(A,mid);
if(块K){
下=中+1;
}
否则{
返回上;
打破
}
}
}
私有静态int calculateBlockCount(int[]数组,int范围){
整数计数=0;
int[]dumie_数组;
int dumie_数组[]。添加[array[0]];
for(int i=0;i范围){
计数++;
dumie_数组=数组[i];
}
否则{
添加(数组[i]);
}
}
返回计数;
}
私有静态int Func_范围(int[]输入){
int范围=0;
范围=最大(输入)-最小(输入)
回报金额;
}
希望仍然有帮助
<>我认为大部分都是用java编写的,只有C++没有的添加功能。(不想通过编写数组来写这么多)但是我认为程序的思想应该是清晰的。
这都是基于这篇文章
.
这是一个非常相似的问题
干杯,
Gijs这些组是否需要包含连续的数字?并且@Koekje he需要将其划分为k个组,并且有N个数字,如果数组已经排序,并且k很小,您将得到复杂性O(N*log(N)),但是您可以通过在减法
O(N)后不进行排序而找到k-1最佳索引来得到O(N)
即使排序是不可避免的,也可以保持不变。例如,就地MSR基数排序。如果所有数组元素的大小与n
无关(例如32位),则此算法是严格线性的。