我不确定该怎么称呼这个问题,因此我找不到它的实例。我在JS写作,但伪代码算法是一个很好的解决方案。
说我想要一篮子3件商品。篮子里有牙膏,牙刷和小苏打。我有三个可供选择的供应商,我可以从不同的供应商中选择每个项目。
我将价格数据存储在二维数组中,如下所示:
productVendors = [
[3,6,2],
[9,4,5],
[1,3,4]
];
每行是不同的供应商,每列是特定产品。 col1 = toothpaste
,col2 = toothbrush
,col3 = baking soda
,例如
productVendors[0][0] = 3
代表第一家供应商的牙膏价格。
我需要一种算法,从 n 供应商处返回每个可能的 n 特定商品。生成的篮子将包含其中每个项目的坐标,而不是价格,如下所示:
//item1 //item2 //item3
basket1 = [{x:0,y:0}, {x:1,y:1}, {x:2,y:2}];
basket2 = [{x:2,y:0}, {x:0,y:1}, {x:1,y:2}];
…
allBaskets = [basket1, basket2, basket3, etc…];
这个java论坛有一个几乎完全相同的问题正在解决,但我不明白。
我想完全理解一个解决方案,不仅有一些有用的东西。第一次在这里提出问题,所以提前感谢任何建议。
答案 0 :(得分:0)
假设有 n 供应商和 n 商品我认为每件商品应来自不同的供应商。这可以按如下方式完成:
arr.filter(item => (item.y == id)).length > 0
答案 1 :(得分:0)
您的输出似乎包含3个可变组件的对象,这些组件可以采用 n 值:
在评论中,您解释说您希望 n n 解决方案,因此这意味着3个组件中的一个是重复的。似乎y坐标和期望结果中的索引是重复的:在您的示例中它们始终是相同的。
这归结为生成所有可能的 n 大小的列表,可以使用 n 值,允许重复。所有商品必须放在一个篮子里,每个商品只能一次,但并非所有供应商都必须由他们代表:购物篮中可能有两件或更多商品来自同一供应商。
您可以使用递归算法。在每个递归级别,我们确定一个特定项目的供应商。所有可能的供应商都会为它进行迭代。对于其中的每一个,都会对所有后续项目进行递归调用,以便生成所有可能性:
function* permutations(n) {
// Produce array [0, ..., n-1]
const arr = [...Array(n).keys()];
function* generate(n) {
if (n < 0) {
yield [...arr]; // a copy of arr
} else {
for (let i = 0; i < arr.length; i++) {
arr[n] = i;
yield* generate(n - 1);
}
}
}
yield* generate(n - 1);
}
// Sample call for n=4
for (let arr of permutations(4)) {
// output permuted arrays as x-y pairs:
console.log(JSON.stringify(arr.map( (x, y) => ({ x, y }))));
// For normal permutation view (without y), replace above line with following:
// console.log(JSON.stringify(arr));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
上述实现使用了一些ES6功能,例如扩展语法(获取可迭代的数组副本),解构(用于交换)和生成器。生成器(function*
)返回一个迭代器,它在它们被生成时提供排列。
在我的第一个版本的答案中,我了解到一个篮子里不可能有重复的供应商。这导致了纯粹的排列问题:
如果必须在每个篮子中代表所有供应商,那么这就成了一个简单的排列问题。
为了生成排列,有几种有效的算法,例如Heap's Algorithm:
function* permutations(n) {
// Produce array [0, ..., n-1]
const arr = [...Array(n).keys()];
function swap(i, j) {
[arr[i], arr[j]] = [arr[j], arr[i]];
}
function* generate(n) {
if (n < 2) {
yield [...arr]; // a copy of arr
} else {
for (let i = 0; i < n - 1; i++) {
yield* generate(n - 1);
swap(n%2 ? 0 : i, n - 1);
}
yield* generate(n - 1);
}
}
yield* generate(n);
}
// Sample call for n=4
for (let arr of permutations(4)) {
// output permuted arrays as x-y pairs:
console.log(JSON.stringify(arr.map( (x, y) => ({ x, y }))));
// For normal permutation view (without y), replace above line with following:
// console.log(JSON.stringify(arr));
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
Heap的算法非常模糊,但他找到了一种模式来选择一个元素与最后一个元素交换,以通过递归产生下一组排列:
在第2步中,似乎总是相同的两个值来回交换(因为 n 在循环中不会改变),但是请注意第一步改变了顺序数组,所以是第一个元素的值,不再是(通常)在步骤1之后。
实际上,在步骤1的每次执行中,最后一个元素将是不同的,因此在完成循环之后,将生成所有排列。
当数组中只考虑一个元素时,递归结束。在这种情况下,不需要交换,并且数组以其当前顺序输出(通过yield
)。
请注意,此算法存在多种错误变体,以及使用基于1的索引的变体,因此在比较这些变体时会变得非常混乱。