【问题标题】:To find minimum elements in array which has sum equals to given value在数组中找到总和等于给定值的最小元素
【发布时间】:2019-04-20 06:24:36
【问题描述】:

我试图找出数组中总和等于的最小元素 给定的输入。我尝试了几个输入总和,但只能找到一个 在第一种情况下配对,而我需要实现的不仅仅是一对。

var arr = [10, 0, -1, 20, 25, 30];
var sum = 45;
var newArr = [];
console.log('before sorting = ' + arr);

arr.sort(function(a, b) {
  return a - b;
});
console.log('after sorting = ' + arr);

var l = 0;
var arrSize = arr.length - 1;

while (l < arrSize) {

  if (arr[l] + arr[arrSize] === sum) {
    var result = newArr.concat(arr[l], arr[arrSize]);
    console.log(result);
    break;
  } else if (arr[l] + arr[arrSize] > sum) {
    arrSize--;
  } else {
    l++;
  }
}

输入数组:[10, 0, -1, 20, 25, 30]

所需总和:45

输出:[20, 25]

我正在努力

所需总和:59

输出:[10, -1, 20, 30]

【问题讨论】:

标签: javascript arrays sorting


【解决方案1】:

这可以看作是一个很适合dynamic programming 的优化问题。

这意味着您可以将其分解为一个递归,该递归试图找到越来越小的数组的最小长度,并根据已删除的内容调整总和。如果您的数组是[10, 0, -1, 20, 25, 30]59,您可以认为最短的是min 的:

[10, ... shortest([ 0, -1, 20, 25, 30], 49)
[0,  ... shortest([10, 20, 25, 30], 49), 59)
[-1, ... shortest([10, 0, 20, 25, 30], 60)
... continue recursively

每次递归,数组都会变短,直到只剩下一个元素。那么问题是该元素是否等于所有减法后剩余的数字。

在代码中更容易显示:

function findMinSum(arr, n){
    if(!arr) return 
    let min 
    for (let i=0; i<arr.length; i++) {

        /* if a number equals the sum, it's obviously
         * the shortest set, just return it
         */
        if (arr[i] == n) return [arr[i]]     
        
        /* recursively call on subset with
         * sum adjusted for removed element 
         */
        let next = findMinSum(arr.slice(i+1), n-arr[i])
        
        /* we only care about next if it's shorter then 
         * the shortest thing we've seen so far
         */
        if (next){
            if(min === undefined || next.length < min.length){
                min = [arr[i], ...next]
            }
        }
    }
    return min && min  /* if we found a match return it, otherwise return undefined */
}

console.log(findMinSum([10, 0, -1, 20, 25, 30], 59).join(', '))
console.log(findMinSum([10, 0, -1, 20, 25, 30], 29).join(', '))
console.log(findMinSum([10, 0, -1, 20, 25, 30], -5)) // undefined when no sum

这在计算上仍然相当昂贵,但它应该比查找所有子集和总和快很多

【讨论】:

    【解决方案2】:

    一种选择是找到数组的all possible subsets,然后通过总和为所需值的那些过滤它们,然后识别具有最小长度的那些:

    const getMinElementsWhichSum = (arr, target) => {
      const subsets = getAllSubsetsOfArr(arr);
      const subsetsWhichSumToTarget = subsets.filter(subset => subset.reduce((a, b) => a + b, 0) === target);
      return subsetsWhichSumToTarget.reduce((a, b) => a.length < b.length ? a : b, { length: Infinity });
    };
    console.log(getMinElementsWhichSum([10, 0, -1, 20, 25, 30], 45));
    console.log(getMinElementsWhichSum([10, 0, -1, 20, 25, 30], 59));
    
    // https://stackoverflow.com/questions/5752002/find-all-possible-subset-combos-in-an-array
    function getAllSubsetsOfArr(array) {
        return new Array(1 << array.length).fill().map(
            (e1,i) => array.filter((e2, j) => i & 1 << j));
    }

    【讨论】:

    • 让我试试这个逻辑
    【解决方案3】:

    试试这个,

    var arr = [10, 0, -1, 20, 25, 30];
    var sum = 29;
    var newArr = [];
    var sum_expected = 0;
    var y = 0;
    while (y < arr.length) {
        for (let i = 0; i < arr.length; i++) {
            var subArr = [];
            sum_expected = arr[i];
            if (arr[i] != 0) subArr.push(arr[i]);
            for (let j = 0; j < arr.length; j++) {
                if (i == j)
                    continue;
                sum_expected += arr[j];
                if (arr[j] != 0) subArr.push(arr[j]);
                if (sum_expected == sum) {
                    var result = arr.filter((el)=>(subArr.indexOf(el) > -1));
                    !newArr.length ? newArr = result : result.length < newArr.length ? newArr = result :  1;
                    break;
                }
            }
        }
        let x = arr.shift();
        arr.push(x);
        y++;
    }
    if (newArr.length) {
        console.log(newArr);
    } else {
        console.log('Not found');
    }

    【讨论】:

    • @MarkMeyer 已修复,谢谢!
    猜你喜欢
    • 2019-09-11
    • 1970-01-01
    • 2022-10-12
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    相关资源
    最近更新 更多