Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 所有小于X的可能性是否仅使用Y数字?_Javascript_Arrays_Math_Numbers_Combinations - Fatal编程技术网

Javascript 所有小于X的可能性是否仅使用Y数字?

Javascript 所有小于X的可能性是否仅使用Y数字?,javascript,arrays,math,numbers,combinations,Javascript,Arrays,Math,Numbers,Combinations,假设我有这些数字:[2,25,37,54,54,76,88,91,99](这些是随机的) 我需要找到那些小于100的数字的所有组合。并非所有数字都必须在这些组合中使用。示例:2,2+25+37,54+25 如何在JavaScript中实现这一点 谢谢如果您有一组数字: var arr = [2, 25, 37, 54, 54, 76, 88, 91, 99] 首先将数组过滤为小于100的数组 var filtered = arr.filter(function(val){ return val

假设我有这些数字:[2,25,37,54,54,76,88,91,99](这些是随机的)

我需要找到那些小于100的数字的所有组合。并非所有数字都必须在这些组合中使用。示例:2,2+25+37,54+25

如何在JavaScript中实现这一点


谢谢

如果您有一组数字:

var arr = [2, 25, 37, 54, 54, 76, 88, 91, 99]
首先将数组过滤为小于100的数组

var filtered = arr.filter(function(val){ return val < 100; });
作为一些糖,您可以使用join很好地格式化结果

console.log('{' + powerSet.join('}{') + '}');
或者,如果您确实希望将其输出为所有集合的集合,则从技术上讲,这更为正确:)

这里有一个


编辑

抱歉,您需要的是总和小于100的所有集合的集合。肯纳贝克是对的。放弃第一步过滤,然后修改powerset方法,使用reduce快速查看数组的和是否小于100:

function powerset(arr) {
    var ps = [[]];
    for (var i=0; i < arr.length; i++) {
        for (var j = 0, len = ps.length; j < len; j++) {
            var arrCandidate = ps[j].concat(arr[i]);
            if (arrCandidate.reduce(function(p, c){ return p + c; }) < 100)
                ps.push(arrCandidate);
        }
    }
    return ps;
}
var pos1 = 0;
var pos2 = -1;
while (pos1 < ps1.length) {
    var arr1 = ps1[pos1];
    while (pos2 + 1 < ps2.length && ps2[pos2+1].sum+arr1.sum < 100) {
        pos2++;
    }
    for (var i = pos2; i >= 0; i--) {
        result.push(arr1.concat(ps2[i]));
    }
    pos1++;
}
功能电源组(arr){
var ps=[[]];
对于(变量i=0;i

这里有一个

如果你只想得到唯一的组合,你可以尝试这样的组合…

(函数(){
“严格使用”;
变量数=[2,25,37,54,54,76,88,91,99],
组合=[];
(功能(){
var temp=[],
len=数字。长度,
总和=0;
对于(变量i=0;i=100 | i==j){
继续;
}
总和+=数字[j];
如果(总和<100){
温度推送(数字[j]);
添加(临时);
}否则{
总和-=数字[j];
}
}
}
}
}());
函数添加(val){
var contains=false,
温度=零;
val.sort(函数(a,b){
返回a-b;
});
temp=val.join(“”);
if(combinations.length==0){
组合。推送(温度拆分(“”);
返回;
}
对于(变量i=0;i
这是的修改版本。使用电源组是蛮力解决方案,虽然简单,但对于大型列表来说效率低下,需要O(2^N)的时间。子集和是NP完全的,所以你不能在指数时间内求解它,但是如果你分而治之,你可以在平均情况下(但不是最坏情况下)1更快地求解它。您要做的是,将阵列分成两半,并在每一半上运行powerset函数(来自Adam的答案),除非您使用阵列保存阵列的总和(事实上,即使您不拆分阵列,保存阵列的总和也会产生巨大的性能提升,因为它可以消除大量冗余添加):

现在,您可以浏览这两个列表并返回总和小于100的数组的每个组合:

function powerset(arr) {
    var ps = [[]];
    for (var i=0; i < arr.length; i++) {
        for (var j = 0, len = ps.length; j < len; j++) {
            var arrCandidate = ps[j].concat(arr[i]);
            if (arrCandidate.reduce(function(p, c){ return p + c; }) < 100)
                ps.push(arrCandidate);
        }
    }
    return ps;
}
var pos1 = 0;
var pos2 = -1;
while (pos1 < ps1.length) {
    var arr1 = ps1[pos1];
    while (pos2 + 1 < ps2.length && ps2[pos2+1].sum+arr1.sum < 100) {
        pos2++;
    }
    for (var i = pos2; i >= 0; i--) {
        result.push(arr1.concat(ps2[i]));
    }
    pos1++;
}
var pos1=0;
var pos2=-1;
while(pos1=0;i--){
结果:推挤(arr1.concat(ps2[i]);
}
pos1++;
}

  • 此解决方案的决策版本(它告诉您,是否存在解决方案?)在O(2^(N/2))时间内运行。如果存在O(1)个解,我预计这将在O(2^(N/2))中运行,而在最坏的情况下,O(2^ N)时间(与未优化的时间相同),其中每个子集都是一个解。在我的测试中,在大小为20-50的列表中,从0到99的随机数(加速比与大小成正比,但我不确定用什么公式计算),它的速度要快2-5倍

  • 这是一种递归方法,也仅适用于非负数组元素:

    function subset_sum( list, upper_bound )
    {
      if( list.length == 1 ) return list[0] < upper_bound ? [list] : [];
      var new_list = list.slice(0); // copy list
      var elem = new_list.pop();
      var combo = elem < upper_bound ? [[elem]] : []; // A
      if( combo.length )
      {
        var lists = subset_sum( new_list, upper_bound-elem ); // B
        combo = combo.concat( lists.map(function(a) { return a.concat(elem); }) );
      }
      return combo.concat(subset_sum( new_list, upper_bound )); // C
    }
    
    var arr = [2, 25, 37, 54, 54, 76, 88, 91, 99];
    var combos = subset_sum(arr,100);
    
    函数子集和(列表,上界)
    {
    if(list.length==1)返回列表[0]<上限?[list]:[];
    var new_list=list.slice(0);//复制列表
    var elem=new_list.pop();
    var combo=elem<上限?[[elem]]:[];//A
    if(combo.length)
    {
    变量列表=子集和(新列表,上界元素);//B
    combo=combo.concat(lists.map(函数(a){返回a.concat(elem);}));
    }
    返回combo.concat(subset_sum(新的_列表,上界));//C
    }
    var-arr=[2,25,37,54,54,76,88,91,99];
    var组合=子集和(arr,100);
    
    下面是JFIDLE:

    基本情况是单元素列表,当且仅当元素小于上限时,答案为其自身

    递归步骤分为3个相互排斥且完整的情况,上面标记为A、B和C:

    • (A) 最后一个元素是单态集,当且仅当它小于上界时
    • (B) 包括最后一个元素的所有其他子集都会被计数,方法是对忽略该元素的列表重复应用函数,并通过该元素减少一个新的上界
    • (C) 通过使用相同的上界对列表递归应用函数,对排除最后一个元素的所有其他子集进行计数
    最后,有26个这样的组合。由于54包含两次,因此也会在输出中重复:

    [99]、[91]、[2,91]、[88]、[2,88]、[76]、[2,76]、[54]、[37,54]、[2,37,54]、[25,54]、[2,25,54]、[2,54]、[37,54]、[2,37,54]、[25,54]、[2,25,54]
    var sum = ps[j].sum + arr[i] //huge optimization! don't redo all the addition
    if (sum < 100) { //don't include this check if negative numbers are allowed
        arrCandidate.sum = sum;
        ps.push(arrCandidate);
    }
    
    ps1.sort(function(b,a){return a.sum-b.sum;});
    ps2.sort(function(a,b){return a.sum-b.sum;});
    
    var pos1 = 0;
    var pos2 = -1;
    while (pos1 < ps1.length) {
        var arr1 = ps1[pos1];
        while (pos2 + 1 < ps2.length && ps2[pos2+1].sum+arr1.sum < 100) {
            pos2++;
        }
        for (var i = pos2; i >= 0; i--) {
            result.push(arr1.concat(ps2[i]));
        }
        pos1++;
    }
    
    function subset_sum( list, upper_bound )
    {
      if( list.length == 1 ) return list[0] < upper_bound ? [list] : [];
      var new_list = list.slice(0); // copy list
      var elem = new_list.pop();
      var combo = elem < upper_bound ? [[elem]] : []; // A
      if( combo.length )
      {
        var lists = subset_sum( new_list, upper_bound-elem ); // B
        combo = combo.concat( lists.map(function(a) { return a.concat(elem); }) );
      }
      return combo.concat(subset_sum( new_list, upper_bound )); // C
    }
    
    var arr = [2, 25, 37, 54, 54, 76, 88, 91, 99];
    var combos = subset_sum(arr,100);