【问题标题】:JavaScript recursive implementation of integer partition without reaarangementJavaScript 递归实现整数分区,无需重新排列
【发布时间】:2015-12-15 20:30:23
【问题描述】:

问题:没有重排的整数分区
输入:非负数 {s1, . . . , sn} 和一个整数 k。
输出:最大的工作是将 S 划分为 k 个或更少的范围,以最小化所有范围的最大总和,而不重新排序任何数字。

示例输入 = [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();

【问题讨论】:

  • 这里有问题还是你只是分享你的代码?
  • 代码不起作用。对于示例输入,它应该返回 1,700 但返回 2,400
  • 什么是i if (i === 1) return S[1]; ?
  • @RiaD 我觉得应该是n

标签: javascript algorithm recursion


【解决方案1】:

如果我理解你的算法:

  • 如果n == 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));

您考虑整个数组,因为S.slice(i).reduce(sum) 从 i 到数组末尾求和,即使从 n 到末尾已经在上一次调用的“尾部”中计算,所以您考虑了两次!

您可以通过告诉 slice 在n 停止来解决:

cost = Math.max(integerPartitionRec(i, k - 1, S), S.slice(i, n).reduce(sum));

或者您可以通过仅将拆分的第一部分传递给递归调用来完全避免使用n

var integerPartitionRec = function(k, S) {
    function sum(p, c) {
        return p + c;
    }

    if (k === 1 || S.length === 1) return S.reduce(sum);

    var cost, min_cost = Number.MAX_VALUE;
    for (var i = 1; i < S.length; i++) {
        cost = Math.max(integerPartitionRec(k - 1, S.slice(0, i)), S.slice(i).reduce(sum));
        min_cost = Math.min(min_cost, cost);
    }

    return min_cost;
};

【讨论】:

  • 我最终将其更改为cost = Math.max(integerPartitionRec(i, k - 1, S, S.slice(i, n).reduce(sum));,但您的回答告诉我出了什么问题。谢谢
  • 是的,这也是一个有效的解决方案,编辑了我的答案以解释问题所在并显示可能的解决方案,如果现在更清楚,请告诉我。
【解决方案2】:

我做了一些随机更改,现在打印为 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)

【讨论】:

  • 你做了一些随机更改?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多