算法在没有碰撞的情况下随机填充数组

时间:2016-08-15 15:30:27

标签: arrays algorithm fill random-access

假设我有一个N个整数的数组设置为值'0',我想选择一个值为'0'的数组的随机元素并将其设置为值'1'

我该如何有效地做到这一点?

我想出了2个解决方案,但它们看起来非常缺乏

第一个解决方案

int array[N] //init to 0s
int n //number of 1s we want to add to the array
int i = 0
while i < n
    int a = random(0, N)
    if array[a] == 0
        array[a] = 1
        i++
    end if
end while

由于碰撞的可能性,大型阵列的效率非常低

第二个涉及包含剩余所有0个位置的列表,我们选择0和剩余0之间的随机数来查找列表中与数组中的索引相对应的值。 它比第一个解决方案更可靠,因为操作数量有限,但如果我们想完全填充数组,仍然会出现N²最坏的情况复杂性

2 个答案:

答案 0 :(得分:3)

你的第二个解决方案实际上是一个好的开始。我假设它涉及在每次更改后重建位置列表,如果要填充整个数组,则使其为O(N²)。但是,您不需要每次都重建列表。既然你想要填充数组,你可以使用随机顺序并相应地选择剩余的位置。

例如,采用以下数组(大小为7,最初不是零):[0, 0, 1, 0, 1, 1, 0]

一旦你建立了零位置列表,这里[0, 1, 3, 6],只需将其随机排序即可获得随机排序。然后按照位置给出的顺序填充数组。

例如,如果shuffle提供[3, 1, 6, 0],那么您可以像这样填充数组:

[0, 0, 1, 0, 1, 1, 0]  <- initial configuration
[0, 0, 1, 1, 1, 1, 0]  <- First, position 3
[0, 1, 1, 1, 1, 1, 0]  <- Second, position 1
[0, 1, 1, 1, 1, 1, 1]  <- etc.
[1, 1, 1, 1, 1, 1, 1]

如果数组最初用零填充,那么它就更容易了。您的初始列表是从0到N(数组大小)的整数列表。将其洗牌并应用相同的过程。

如果你不想填满整个数组,你仍然需要构建整个列表,但是你可以在改组后截断它(这意味着在某个点之后停止填充数组)。

当然,此解决方案要求阵列在每个步骤之间不会发生变化。

答案 1 :(得分:2)

您可以使用n个和N-n零填充数组并进行随机随机播放。

Fisher-Yates shuffle具有线性复杂性:

for i from N−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]