[英]How to generate natural numbers not less than X and not more than Y, consisting of the same digits?
[英]All possibilities that are less than X using only Y numbers?
說我有這些數字:[2,25,37,54,54,76,88,91,99](這些是隨機的)
我需要找到那些小於100的數字的所有組合。並非所有數字都必須在這些組合中使用。 例子:2,2 + 25 + 37,54 + 25
我怎樣才能在JavaScript中實現這一目標?
謝謝
這是子集和問題的修改版本。 獲取功率集是一種強力解決方案,雖然簡單,但對於大型列表來說效率低,需要O(2 ^ N)時間。 子集和是NP完全的,所以你不能在低於指數的時間內解決它,但如果你分而治之,你可以在一般情況下更快地解決它(但不是最壞的情況) 1 。 你做的是,將數組分成兩半並在每一半上運行powerset函數(來自Adam的答案),除了你用數組保存數組的總和(實際上,保存數組的總和會產生巨大的性能)即使你不拆分數組也會提升,因為它可以消除大量的冗余添加):
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;});
現在,您可以瀏覽兩個列表並返回總和小於100的數組的每個組合:
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 arr = [2, 25, 37, 54, 54, 76, 88, 91, 99]
首先將數組過濾到小於100的數組
var filtered = arr.filter(function(val){ return val < 100; });
現在您需要找到這些數字的冪集。
它看起來像有一個代碼示例這里 ,將實現這一目標。
摘抄
function powerset(arr) {
var ps = [[]];
for (var i=0; i < arr.length; i++) {
for (var j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(arr[i]));
}
}
return ps;
}
所以你要接受
var powerSet = powerset(filtered);
而作為一些糖,您可以使用join很好地格式化結果
console.log('{' + powerSet.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;
}
這是一個更新的演示
如果你想只獲得獨特的組合,你可以試試這樣的......
的jsfiddle
(function () {
"use strict";
var numbers = [2, 25, 37, 54, 54, 76, 88, 91, 99],
combinations = [];
(function () {
var temp = [],
len = numbers.length,
sum = 0;
for (var i = 0; i < len; i++) {
temp.length = 0;
sum = numbers[i];
if (sum < 100) {
temp.push(sum);
add(temp);
for (var j = 0; j < len; j++) {
if (numbers[j] >= 100 || i === j) {
continue;
}
sum += numbers[j];
if (sum < 100) {
temp.push(numbers[j]);
add(temp);
} else {
sum -= numbers[j];
}
}
}
}
}());
function add(val) {
var contains = false,
temp = null;
val.sort(function (a, b) {
return a - b;
});
temp = val.join(" ");
if (combinations.length === 0) {
combinations.push(temp.split(" "));
return;
}
for (var i = 0; i < combinations.length; i++) {
if (combinations[i].join(" ") === temp) {
contains = true;
}
}
if (!contains) {
combinations.push(temp.split(" "));
}
}
}());
這是一種遞歸方法,也只適用於非負數組元素:
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);
這是jfiddle: http : //jsfiddle.net/bceHr/4/
基本情況是單元素列表,當且僅當元素小於上限時,答案本身。
遞歸步驟分為3個互斥和完整的情況,上面標記為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],[54],[37,54],[2,37,54],[25,54],[2, 25,54],[2,54],[37],[25,37],[2,25,37],[2,37],[25],[2,25],[2]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.