这是Python
3代码,可在
0.28几秒钟内生成1000000个“随机”小写字母(另请参阅
0.11-seconds解决方案;问题中的@Ashwini
Chaudhary的代码
0.55在我的计算机上需要几秒钟,@ Markku K.的代码-
0.53):
#!/usr/bin/env python3import osimport sysdef write_random_lowercase(n): min_lc = ord(b'a') len_lc = 26 ba = bytearray(os.urandom(n)) for i, b in enumerate(ba): ba[i] = min_lc + b % len_lc # convert 0..255 to 97..122 sys.stdout.buffer.write(ba)write_random_lowercase(1000000)
% len_lc尽管它仍然满足条件(ascii,小写字母,1、2、3个字母序列的频率),但使分布偏斜(请参阅最后的解决方法):
$ python3 generate-random.py | python3 check-seq.py
在哪里
check-seq.py:
#!/usr/bin/env python3import sysfrom collections import Counterfrom string import ascii_lowercasedef main(): limits = [40000, 2000, 100] s = sys.stdin.buffer.readline() # a single line assert 1000000 <= len(s) <= 1000002 # check length +/- newline s.depre('ascii','strict') # check ascii assert set(s) == set(ascii_lowercase.enpre('ascii')) # check lowercase for n, lim in enumerate(limits, start=1): freq = Counter(tuple(s[i:i+n]) for i in range(len(s))) assert max(freq.values()) <= lim, freqmain()注意:在acm.timus.ru上
generate-random.py给出“超出输出限制”。
为了提高性能,您可以使用
bytes.translate()方法(
0.11秒):
#!/usr/bin/env python3import osimport sys# make translation table from 0..255 to 97..122tbl = bytes.maketrans(bytearray(range(256)),bytearray([ord(b'a') + b % 26 for b in range(256)]))# generate random bytes and translate them to lowercase asciisys.stdout.buffer.write(os.urandom(1000000).translate(tbl))
如何解决% len_lc
偏斜
256(字节数)不能被
26(低拉丁字母数)均分,因此该公式
min_lc + b % len_lc使某些值出现的频率比其他值少,例如:
#!/usr/bin/env python3"""Find out skew: x = 97 + y % 26 where y is uniform from [0, 256) range."""from collections import Counter, defaultdictdef find_skew(random_bytes): char2freq = Counter(chr(ord(b'a') + b % 26) for b in random_bytes) freq2char = defaultdict(set) for char, freq in char2freq.items(): freq2char[freq].add(char) return {f: ''.join(sorted(c)) for f, c in freq2char.items()}print(find_skew(range(256)))# -> {9: 'wxyz', 10: 'abcdefghijklmnopqrstuv'}这里,输入
range(256)是均匀分布的(每个字节正好一次出现),但
'wxyz'在输出信往往小于其余部分
9与
10发生。要解决此问题,可以丢弃未对齐的字节:
print(find_skew(range(256 - (256 % 26))))# -> {9: 'abcdefghijklmnopqrstuvwxyz'}在此,输入是均匀分布的字节,
[0, 234)输出范围是均匀分布的ascii小写字母。
bytes.translate()接受第二个参数来指定要删除的字节:
#!/usr/bin/env python3import osimport sysnbytes = 256nletters = 26naligned = nbytes - (nbytes % nletters)tbl = bytes.maketrans(bytearray(range(naligned)),bytearray([ord(b'a') + b % nlettersfor b in range(naligned)]))bytes2delete = bytearray(range(naligned, nbytes))R = lambda n: os.urandom(n).translate(tbl, bytes2delete)def write_random_ascii_lowercase_letters(write, n): """*write* *n* random ascii lowercase letters.""" while n > 0: # R(n) expected to drop `(nbytes - nletters) / nbytes` bytes # to compensate, increase the initial size n -= write(memoryview(R(n * nbytes // naligned + 1))[:n])write = sys.stdout.buffer.writewrite_random_ascii_lowercase_letters(write, 1000000)
如果随机生成器(
os.urandom此处)产生的长字节序列超出了对齐范围(
>=234),则
while循环可能执行多次。
如果
random.getrandbits(8*n).to_bytes(n,'big')使用代替,则时间性能可以提高另一个数量级
os.urandom(n)。前者使用Mersenne
Twister作为核心生成器,它可能比
os.urandom()使用操作系统提供的源更快。如果将随机字符串用于机密,则后者更为安全。



