我想伪随机创建一个包含48个条目的列表——24个0和24个1——其中0和1在一行中重复的次数都不超过两次。例如:

[1,1,0,1,0,0,1,1,0,1,0,...]

import random
l = list()
for i in range(48):
    if len(l) < 2:
        l.append(random.choice([0,1]))
    else:
        if l[i-1] == l[i-2]:
            if l[i-1] == 0:
                l.append(1)
            else:
                l.append(0)
        else:
            l.append(random.choice([0,1]))

我有上面的代码,但它有时返回不均匀的1或0计数。所有可能的解决方案应该有相同的机会出现。

最佳答案

这里有一个函数,它接受一个整数n并返回一个包含n0s和n1s的列表。
它遵循“行中的3号约束”,首先随机选择整数0或1中的一个,然后尝试通过随机选择位置并检查在该位置插入整数是否会违反该约束来将其插入列表中的某个位置。如果没有,它会将其插入其中,否则它会随机选择不同的位置进行尝试。它一直持续到所有n0s和所有n1s都被放到列表中的某个位置
它通过在0和1被插入到列表中之后为它们分别递减一个计数器来跟踪到目前为止使用了多少个0和1。如果没有更多的0要添加,它将添加其余的1(反之亦然)。
当列表的长度达到2*n时,函数返回该列表(所有的0和1都已用完)

import random

def pseudo_rand(n):
    left = {0: n, 1: n} # keep track of how many 1s or 0s you can still use
    out = []
    while len(out) < n*2:
        i = random.randint(0,1) # select 0 or 1 randomly
        if not left[i]: # if have already used up all the 0s or 1s, use the other one instead
            i = 1-i
        possible_pos = list(range(len(out)+1)) # make a list of possible indexes to insert i
        while possible_pos:
            pos = random.choice(possible_pos)
            bottom = max(pos-2, 0)
            top = pos+2
            dz = out[bottom:top] # danger zone: range to inspect to see if we can insert i at position pos
            if not any(i == dz[j] and i == dz[j-1] for j in range(1, len(dz))): # if inserting i at position pos won't violate the 'no 3 in a row constraint'
                out.insert(pos, i)
                left[i] -= 1
                break
            else: # otherwise don't consider this position anymore
                possible_pos.remove(pos)
    return out

一些例子:
>>> pseudo_rand(24)
[1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]

>>> pseudo_rand(5)
[1, 0, 0, 1, 0, 0, 1, 1, 0, 1]

07-24 20:04