【问题标题】:Finding closest sum of numbers to a given number查找与给定数字最接近的数字总和
【发布时间】:2020-02-15 15:03:57
【问题描述】:

假设我有一个列表 [1,2,3,4,5,6,7] 我想找到最接近给定数字的数字总和。对不起,糟糕的解释,但这里有一个例子:

假设我有一个列表 [1,2,3,4,5,6,7] 我想找到最接近 10 的数字。

然后该方法应该返回 6 和 4 或 7 和 3,因为它最接近 10。所以 5 + 4 是错误的,因为那是 9,他可以得到 10。

另一个例子:你想要最接近 14 的,那么他应该返回 7 和 6

如果您有任何问题,请提出,因为很难解释我想要什么:P

【问题讨论】:

  • 您可以使用数组中的任何项目多少次?例如:如果给定的数字是 10,那么你可以得到 10 乘以 1 的总和以得到 10。另外:这看起来像一个学校问题。
  • 到目前为止你尝试了什么?
  • 是否允许2+3+5
  • @peter 您能否为您的问题添加更多细节?它相当混乱。
  • 如果输入数字是28怎么办?

标签: javascript php


【解决方案1】:

combinelocationOf 的函数取自不同作者的不同答案。

printClosest([0.5,2,4] , 5);
printClosest([1, 2, 3, 4, 5, 6, 7], 28);
printClosest([1, 2, 3, 4, 5, 6, 7], 10.9);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 2);
printClosest([1, 2, 3, 4, 5, 6, 7], 10, 3);
printClosest([1, 2, 3, 4, 5, 6, 7], 14, 2);

function printClosest(array, value, limit) {
  var checkLength = function(array) {
    return array.length === limit;
  };
  var combinations = combine(array); //get all combinations
  combinations = limit ? combinations.filter(checkLength) : combinations;//limit length if required
  var sum = combinations.map(function(c) { //create an array with sum of combinations
    return c.reduce(function(p, c) {
      return p + c;
    }, 0)
  });
  var sumSorted = sum.slice(0).sort(function(a, b) {//sort sum array
    return a - b;
  });

  index = locationOf(value, sumSorted);//find where the value fits in
  //index = (Math.abs(value - sum[index]) <= Math.abs(value - sum[index + 1])) ? index : index + 1;
  index = index >= sum.length ? sum.length - 1 : index;
  index = sum.indexOf(sumSorted[index]);//get the respective combination

  console.log(sum, combinations, index);

  document.getElementById("result").innerHTML += "value : " + value + " combi: " + combinations[index].toString() + " (limit : " + (limit || "none") + ")<br>";
}


function combine(a) {
  var fn = function(n, src, got, all) {
    if (n == 0) {
      if (got.length > 0) {
        all[all.length] = got;
      }
      return;
    }
    for (var j = 0; j < src.length; j++) {
      fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
    }
    return;
  }
  var all = [];
  for (var i = 0; i < a.length; i++) {
    fn(i, a, [], all);
  }
  all.push(a);
  return all;
}

function locationOf(element, array, start, end) {
  start = start || 0;
  end = end || array.length;
  var pivot = parseInt(start + (end - start) / 2, 10);
  if (end - start <= 1 || array[pivot] === element) return pivot;
  if (array[pivot] < element) {
    return locationOf(element, array, pivot, end);
  } else {
    return locationOf(element, array, start, pivot);
  }
}
&lt;pre id="result"&gt;&lt;pre&gt;

【讨论】:

  • 是的,真的很好,这就是我要找的东西,你能不能让我寻找最接近 5 的数字总和不能大于 5?像这样:[0.5,2,4] 最接近的是 4+2 但总和不能大于 5 所以他会取 2 + 0.5
  • 是的,有可能,我只是为此注释掉了一行。看到10.9 给出3,7,如果您取消注释该行,它将给出4,7,因为11接近10.9。请随时根据您的要求进行更改:)
  • 算法采用 4,0.5 而不是 2,0.5 :)
  • 哦,是的,我自己弄错了,我的意思是 4 + 0.5 of course xD
【解决方案2】:
 var data= [1, 2, 3,4,5,6,7];
  var closest = 14;
 for (var x = 0; x < data.length; x++) {
    for (var y = x+1; y < data.length; y++) {
             if(data[x] + data[y] == closet){
                     alert(data[x].toString() + "  " + data[y].toString());
                }
            }
       }

【讨论】:

  • OP 说我想找到最接近的数字总和。您只是在这里提醒确切的金额。
  • 是的,我想找到数字的总和,仍然感谢您的帮助:)
【解决方案3】:

根据我从您的问题中了解到的情况,我制作了这个 sn-p。我假设您不想两次使用相同的数字(例如 14 => 7 + 7)。

它正在与您的示例一起使用。

var arr = [1, 2, 3, 4, 5, 6, 7];

var a = 0, b = 0;
var nb = 14;

for(var i in arr) {
  for(var j in arr) {
    if(i != j) {
      var tmp = arr[i] + arr[j];
      if(tmp <= nb && tmp > a + b) {
        a = arr[i];
        b = arr[j];
      }
    }
  }
}

document.write("Closest to " + nb + " => " + a + " + " + b);

【讨论】:

  • 对不起,我有点不清楚,但我希望它可以处理多个数字,例如,如果您有 [1,2,3,4,5,6,7] 并且您将拥有最接近的到 19 那么答案应该是 7 + 6 + 5 + 1 而不是 7 + 6 + 5 + 1 ,感谢您帮助我感谢它:) 也允许相同的数字两次 :)
  • 这只能找到一个可能的答案。它无法处理一个值在输入集中多次出现的情况。它在边界内而不是最接近目标的地方找到解决方案。
  • @Peter 相同的数字只有在数组中出现两次时才允许出现两次,对吗?根据您的问题,我假设您只想要两个术语的总和,所以...我误解了:/
  • @PierreC.是的,是的,是的,对不起,我的问题真的很令人困惑,抱歉,感谢您抽出时间帮助我 :)
【解决方案4】:

我对这个问题有一个有点冗长的解决方案,这样更容易看出做了什么。

以下解决方案的主要好处:

  • 第二个循环不会再次从数组的开头开始。我的意思是,第二个循环的 loop_boundary 不是像通常那样设置为 0,而是从下一个索引开始。如果您的数字数组很长,这会有所帮助。但是,如果它像示例中那样短,则对性能的影响是最小的。将第一个循环的边界减一将防止错误发生。
  • 即使想要的数字是 1 或负数也能正常工作。

小提琴:

JSFiddle

代码:

var numbers = [1,2,3,4,5,6,7];
var wanted_number = 1;
var closest_range, closest1, closest2 = null;

var loop1_boundary = numbers.length-1;
for(var i=0; i<loop1_boundary; i++) {

    var start_index = i+1;
    var loop2_boundary = numbers.length;

    for(var k=start_index; k<loop2_boundary; k++) {

        var number1 = parseInt(numbers[i]);
        var number2 = parseInt(numbers[k]);

        var sum = number1 + number2;
        var range = wanted_number - sum;

        document.write( number1+' + '+number2 +' < '+closest_range+'<br/>' );

        if(Math.abs(range) < Math.abs(closest_range) || closest_range == null ) {
            closest_range = range;
            closest1 = number1;
            closest2 = number2;
        }

    }

    if(range==0){
        break;
    }
}

document.write( 'closest to given number was '+closest1+' and '+closest2+'. The range from wanted number is '+closest_range );

【讨论】:

  • 对不起,我有点不清楚,但我希望它可以处理多个数字,例如,如果您有 [1,2,3,4,5,6,7] 并且您将拥有最接近的到 19 那么答案应该是 7 + 6 + 5 + 1 而不是 6 + 7 ,感谢您帮助我感谢它:)
【解决方案5】:

此提议生成所有可能的组合,将它们收集到一个对象中,该对象将总和作为键,然后过滤最接近给定值的总和。

function getSum(array, sum) {
    function add(a, b) { return a + b; }

    function c(left, right) {
        var s = right.reduce(add, 0);
        if (s > sum) {
            return;
        }
        if (!result.length || s === result[0].reduce(add, 0)) {
            result.push(right);
        } else if (s > result[0].reduce(add, 0)) {
            result = [right];
        }
        left.forEach(function (a, i) {
            var x = left.slice();
            x.splice(i);
            c(left.slice(0, i), [a].concat(right));
        });
    }

    var result = [];
    c(array, [], 0);
    return result;
}

function print(o) {
    document.write('<pre>' + JSON.stringify(o, 0, 4) + '</pre>');
}

print(getSum([1, 2, 3, 4, 5, 6, 7], 10));
print(getSum([1, 2, 3, 4, 5, 6, 7], 14));
print(getSum([1, 2, 3, 4, 5, 6, 7], 19));

【讨论】:

  • 对不起,我有点不清楚,但我希望它可以处理多个数字,例如,如果您有 [1,2,3,4,5,6,7] 并且您将拥有最接近的到 19 那么答案应该是 7 + 6 + 5 + 1 而不是 6 + 7 ,感谢您帮助我感谢它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 2021-08-09
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多