Javascript 所有小于X的可能性是否仅使用Y数字?
假设我有这些数字:[2,25,37,54,54,76,88,91,99](这些是随机的) 我需要找到那些小于100的数字的所有组合。并非所有数字都必须在这些组合中使用。示例:2,2+25+37,54+25 如何在JavaScript中实现这一点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
谢谢如果您有一组数字:
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++;
}
这是一种递归方法,也仅适用于非负数组元素:
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) 通过使用相同的上界对列表递归应用函数,对排除最后一个元素的所有其他子集进行计数
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);