假设我有一个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²最坏的情况复杂性
答案 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]