问题:没有重新排列的整数分区
输入:非负数的排列S {s1,... 。 。 ,sn}和整数k。
输出:将S划分为k个或更少范围的最大工作,以最小化所有范围的最大总和,而无需重新排序任何数字。
示例input = [100, 200, 300, 400, 500, 600, 700, 800, 900]
应该输出最大的作业,只有1,700,因为数组最好是按100 200 300 400 500 | 600 700 | 800 900
进行分区。
我的功能不起作用。例如,当输出1,700时输出2,400。无法弄清楚是什么错误。
var integerPartitionRec = function(n, k, S) {
function sum(p, c) {
return p + c;
}
if (i === 1) return S[1];
if (k === 1) return S.slice(0, n).reduce(sum);
var cost, min_cost = Number.MAX_VALUE;
for (var i = 1; i < n; i++) {
cost = Math.max(integerPartitionRec(i, k - 1, S), S.slice(i).reduce(sum));
min_cost = Math.min(min_cost, cost);
}
return min_cost;
};
var run = function() {
var test = [100, 200, 300, 400, 500, 600, 700, 800, 900];
console.log(integerPartitionRec(test.length, 3, test));
};
run();
答案 0 :(得分:2)
如果我理解你的算法:
n == 1
您有一个大小为1的数组,您无法拆分,那么最佳解决方案是不拆分并返回元素的值,该值也是整个数组的总和:{ {1}}(您错误地提出了S[0]
)S[1]
你不能分裂,那么返回整个数组的总和k == 1
和最后i=0
,因为这些是假分裂,如果你可以分开它总是最好这样做),检查结果是什么,并采取最佳分割。但是在递归调用中,你应该只考虑最多i=n
的数组,而在你的代码中,在这一行中:
n
你考虑整个数组,因为cost = Math.max(integerPartitionRec(i, k - 1, S), S.slice(i).reduce(sum));
从i加到数组的末尾,即使从S.slice(i).reduce(sum)
到结尾已经在&#34; tail&#34;之前的通话,所以你考虑两次!
您可以通过告诉切片停在n
:
n
或者您可以通过仅将分割的第一部分传递给递归调用来完全避免使用cost = Math.max(integerPartitionRec(i, k - 1, S), S.slice(i, n).reduce(sum));
:
n
答案 1 :(得分:1)
我做了一些随机的更改,它现在打印1700
var integerPartitionRec = function(n, k, S) {
function sum(p, c) {
return p + c;
}
if (n === 1) return S[1];
if (k === 1) return S.slice(0, n).reduce(sum);
var cost, min_cost = Number.MAX_VALUE;
for (var i = 1; i < n; i++) {
cost = Math.max(integerPartitionRec(i, k - 1, S), S.slice(i, n).reduce(sum));
min_cost = Math.min(min_cost, cost);
}
return min_cost;
};
var run = function() {
var test = [100, 200, 300, 400, 500, 600, 700, 800, 900];
console.log(integerPartitionRec(test.length, 3, test));
};
run();
但我宁愿使用另一种算法:您可以在答案上使用二进制搜索,然后检查O(n)
是否可以将数组划分为k
个部分,其中每个部分都小于某个常数。它将是O(n log sum)
而不是O(n^2)