假设我有一个具有不同商品价格的数组。
var myItemsEuro = [0.34, 0.11, 0.5, 0.33, 0.05, 0.13, 0.23, 3.22, 1.94]
我想有这样的功能:
function getTradeItems(0.89) { //The price of the item I want to buy
//Calculate, which of my items should be used to buy the item for 0.89€
return [0, 3, 6] //The position of my items in the array, which added together equal 0.90€
}
清理事项:
我有一盒带有pricetags的物品(myItemsEuro)。我想买一件物品,用我的物品作为付款。如果我用至少1美分多付钱,另一方将接受我的交易。
该功能应该有效,所以我可以将其他人的价格传递给它(例如0.89)并返回,我将不得不放弃哪些物品。这些项目的组合必须高于0.89美分(至少0.9),但应尽可能低!
我是JS的新手,我正在考虑计算我项目的每一个组合,然后使用与buyprice差异最小的项目。这对我来说似乎很复杂,我甚至不知道如何计算每一个组合,还保存用于计算的项目。
有没有办法更有效地实现这一目标?我真的不希望这里有任何完美的代码,一点点帮助才能进入正确的方向也很不错。
任何帮助表示赞赏! :)
修改:
很抱歉错过了我自己的尝试。只是我根本不知道如何解决这个问题。不 - 不是作业 - 这应该是我正在努力的chromeextension的一部分!
var myItemsEuro = [0.34, 0.11, 0.5, 0.33, 0.05, 0.13, 0.23, 3.22, 1.94]
function getTradeItems(marketPrice) {
var result = 0;
var positions = [];
for(i = 0; i < myItemsEuro.length; i++) {
result += myItemsEuro[i]; //add numbers from the array
positions.push(i); //save the used numbers position
if(result > marketPrice) { //if result is greater than marketPrice...
console.log(result)
console.log(positions)
return positions; //return positions in the array
}
}
}
getTradeItems(1.31);
修改
对数组进行排序然后添加数字并不能提供解决方案。
var x = 1.18;
//Sorted by numbers
var myItemsEuro = [0.05, 0.11, 0.13, 0.20, 0.35, 0.50, 0.60, 0.69, 0.75];
//Add together and stop when sum > x:
0.05 + 0.11 + 0.13 + 0.20 + 0.35 + 0.50 = 1.34
//Best solution would be adding [6] and [8] from the array
0.50 + 0.69 = 1.19
答案 0 :(得分:0)
如果项目大于或等于target
,您可以使用暴力方法测试项目的所有组合。
基本考虑是将计数器从零到2 values.length 并检查实际的2 index 是否是具有{{3的计数器的一部分}}。如果是这样,请从索引中获取值并将其放入parts
数组。
然后构建sum
的{{1}}并检查parts
是否大于或等于sum
且可能小于target
sum
} array,然后将结果移动到结果数组。如果result
等于sum
,则将实际的result[0].sum
和parts
推送到sum
。
此提案适用于未排序的值,但如果大于result
值的值未包含在要处理的数组中,则可能更有效。
另一个缺点是,bitwise AND &
仅适用于32位,这意味着不能使用超过32项的数组。
target
&#13;
var values = [0.34, 0.11, 0.5, 0.33, 0.05, 0.13, 0.23, 3.22, 1.94],
target = 0.90,
i,
l = 1 << values.length,
result = [],
parts,
sum;
for (i = 0; i < l; i++) {
parts = values.filter(function (_, j) {
return i & 1 << j;
});
sum = parts.reduce(function (a, b) { return a + b; }, 0);
if (sum >= target) {
if (!result.length || sum < result[0].sum) {
result = [{ parts: parts, sum: sum }];
continue;
}
if (sum === result[0].sum) {
result.push({ parts: parts, sum: sum });
}
}
}
console.log(result);
&#13;
答案 1 :(得分:0)
我建议采取一些措施:
我建议的解决方案一旦明确继续添加项目就没有任何意义,将立即回溯。至少有两种情况可以得出这个结论(停止递归搜索):
以下是建议的代码:
function getTradeItems(target, items) {
var best = -1e20, // should be maximised up to -1 if possible
bestTaken = [], // indices of the best selection
bestCount = 0, // number of selected items in best solution
// Multiply all amounts by 100 to avoid floating point inaccuracies:
cents = items.map( euro => Math.round(euro * 100) );
function recurse(target, i, count) {
if (target < 0) { // Found potential solution
// Backtrack if this is not better than the best solution
// found so far. If a tie, then minimise the number of selected items
if (target < best ||
target === best && count > bestCount) return false;
best = target;
bestTaken = [];
bestCount = count;
return true;
}
// Give up when there's not enough item value available
if (i >= cents.length) return null;
// Include the item at index i:
var res1 = recurse(target - cents[i], i+1, count+1);
// If we could not reach the target, don't lose time retrying
// without this item:
if (res1 === null) return null;
// Exclude the item at index i:
var res0 = recurse(target, i+1, count);
// If neither led to a solution...
if (!res0 && !res1) return false;
// If the best was to include the item, remember that item
if (!res0) bestTaken.push(i);
return true;
}
recurse(Math.round(target * 100), 0);
return bestTaken.reverse();
}
// Sample input
var myItemsEuro = [0.05, 0.11, 0.13, 0.20, 0.35, 0.50, 0.60, 0.69, 0.75];
var x = 1.18
// Get the best item selection
var result = getTradeItems(x, myItemsEuro);
// Output result
console.log('Selected: ', result.join()); // 5, 7
// Show corresponding sum: (1.19)
console.log('Sum: ', result.reduce( (sum, i) => sum + myItemsEuro[i], 0).toFixed(2));
&#13;