假设我有以下数组:
array = [0, 1, 2, ... , n]
如何找到一个集合,使得集合中的对都是唯一且非重复的元素?
这意味着:
•(x,y)=(y,x)所以如果(x,y)在集合中,则(y,x)不会是,反之亦然
•如果一个元素已经被使用,则不能再次使用。
例如:如果(1,2)在集合中,则集合中不能有一对具有1或2的对。
上下文: 我正在创建一个将硬币放置在2n个元素板上的记忆游戏。我希望游戏的每次迭代都将元素放置在板上的随机空间中。
例如:
Suppose I have: [A, B, C, D, E, F]
Since [A, B, C, D, E, F] is length 6, then the board will consist of 12 elements.
My board will look like the following such that the elements were randomly placed:
A B C D
C A F B
E F E D
坦率地说,不做O(n ^ 2)蛮力方法,我不知道如何解决这个问题。我认为可能还有另一种更有效的算法。
答案 0 :(得分:1)
您可以使用Fisher–Yates shuffle来以O(n)时间有效地对每个硬币值中的两个硬币值进行随机排列。算法基本上采用排序列表,并不断交换列表中的两个随机元素,直到列表在数学上被重新排序/随机为止。
在JavaScript中:
// Generate seed array.
// Numbers are used here for simplicity, but the array can contain any type like String.
a = [];
for (i=0; i<4; i++) { a.push(i, i); }
console.log(a); // [0, 0, 1, 1, 2, 2, 3, 3]
// This is the "modern version" pseudo-code ported to JavaScript:
// To shuffle an array a of n elements (indices 0..n-1):
n = a.length;
// for i from n−1 downto 1 do
for (i=n-1; i>0; i--) {
// j ← random integer such that 0 ≤ j ≤ i
j = Math.floor(Math.random() * (i + 1));
// exchange a[j] and a[i]
tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
console.log(a); // [2, 1, 3, 3, 0, 1, 0, 2]
旁注:即使您算法中的O(n ^ 2)听起来很糟糕,但对洗牌游戏中的物品进行整理可能并没有多大区别。您一开始只将少量项目洗牌。因此,您可能无法判断复杂度是O(n)还是O(n ^ 2)。复杂度仅在n变得非常大时才变得重要,或者您需要连续重复计算(例如每秒数百万次)。我建议首先优化代码以提高可读性。然后仅在明显需要时进行优化。
答案 1 :(得分:0)
创建两个输入数组(或一个包含重复元素的数组)。从数组中随机逐出元素,并将其随机放置在3个输出数组中。您无需随机洗它们,因为您可以随机选择元素并随机放置。
在您的代码中,您可以检查是否在输出数组中,给定索引上是否存在元素,以避免覆盖。