【问题标题】:Find elements in an integer array such that their sum is X and sum of their square is least查找整数数组中的元素,使得它们的和为 X 且它们的平方和最小
【发布时间】:2014-11-08 11:54:59
【问题描述】:

给定一个长度为n 的数组arr,找到arr 中的任何元素,使得它们的和为x 并且它们的平方和最小。我试图找到复杂度最低的算法。到目前为止,我已经编写了一个简单的递归算法,可以找到数组中的所有子集并将总和检查作为基本条件。我写的代码是 javascript 如下:

var arr = [3, 4, 2, 1];
var arr2 = arr.map(function(n) { return n*n; });

var max_sum = 5;
var most_min = -1;

function _rec(i, _sum, _square) {
    if(_sum >= max_sum) {
        if(most_min == -1 || _square < most_min) {
            most_min = _square;
            console.log("MIN: " + most_min);
        }
        console.log("END");
        return;
    }

    if(i >= arr.length)
        return;

    console.log(i);
    var n = arr[i];
    // square of above number
    var n2 = arr2[i];    
    _sum = _sum + n;
    _square = _square + n2;
    _rec(i+1, _sum, _square);

    _sum = _sum - n;
    _square = _square - n2;
    _rec(i+1, _sum, _square);
}

_rec(0, 0, 0);

访问http://jsfiddle.net/1dxgq6d5/6/查看上述算法的输出。上述算法非常简单,它通过在每个递归步骤评估两个选择来找到所有子集; 1) 选择当前数字或 2) 拒绝然后继续递归。

我正在尝试找到一种比上面的简单递归更有效的算法。任何建议或帮助将不胜感激。

另一个假设

我在想,如果我对数组进行排序,并找到具有最小方差(彼此之间的分隔)的元素子集,使得它们的总和为 x 将满足我的要求。不确定这是否会很有帮助,但我目前正在努力改进我目前的盲递归方法。

【问题讨论】:

  • 最小方差很有用,使用大量小数字而不是单个更大的数字也是如此:例如,使用 4 和 6 比使用 10 更好。

标签: algorithm recursion data-structures


【解决方案1】:

首先,您找到的是子集,而不是排列,因为您不关心每个集合中元素的顺序。

其次,即使不尝试最小化平方和,只要找出总和为目标数的子集是否是 NP 完全的——这就是subset sum problem。目前大多数计算机科学家认为 P != NP,因此没有有效的(多项式时间)算法。

【讨论】:

    【解决方案2】:

    子集总和只是弱 NP-hard,因此可以通过动态规划获得有效的解决方案(假设输入数组由总和相对较小的整数组成)。通过将前 k 个元素的可能性存储在数组中,从递归和深度优先尝试所有可能性切换到迭代和广度优先尝试所有可能性。在考虑元素 k + 1 之前,通过丢弃除可以得到的每个总数的最小平方和之外的所有元素来过滤此数组。

    【讨论】:

    • 感谢您的评论。我使用动态规划方法来实现高效算法
    【解决方案3】:

    我以比简单递归更有效的方式解决了这个问题。我正在使用动态编程方法。下面是我写的python代码:

    _sum=7
    _set=[1,1,2,3,4,6]
    
    current_idx = 0
    
    sum_mapping = [[-1 for i in range(len(_set) + 1)] for i in range(_sum)]
    max_sum = _set[current_idx]
    for i in range(0, _sum):
        current_sum = i + 1
        for j in [i for i in range(0, current_idx+1)][::-1] + \
            [i for i in range(current_idx + 1, len(_set))]:
            required_value = current_sum - _set[j]
            if required_value < 0:
                break
            if required_value == 0 or sum_mapping[required_value - 1][j] != -1:
                _j = j + 1
                sum_mapping[i][_j:] = [j]*(len(_set) - j)
                break
        if max_sum == current_sum:
            current_idx = current_idx + 1
            max_sum = max_sum + _set[current_idx]
    
    _cur = sum_mapping[_sum-1][len(_set)]
    
    if _cur != -1:
        _l_sum = _sum
        while _l_sum != 0:
            print(_set[_cur])
            _l_sum = _l_sum - _set[_cur]
            _cur = sum_mapping[_l_sum -1][len(_set)]
    

    这里是 ideone 输出:http://ideone.com/OgGN2f

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 2019-05-03
      • 1970-01-01
      • 2011-08-23
      • 1970-01-01
      • 2013-12-15
      相关资源
      最近更新 更多