【问题标题】:All numbers in a given range but random order给定范围内的所有数字,但顺序随机
【发布时间】:2017-12-02 18:51:56
【问题描述】:

假设我想以随机顺序生成 1-1000 的所有整数。但是……

  • 生成的数字不会超过一次
  • 不存储所有可能数字的数组、列表...
  • 不存储已经生成的数字。
  • 最后没有遗漏任何数字。

我认为这应该是不可能的,但也许我只是没有考虑正确的解决方案。

我想在 C# 中使用它,但我对方法比实际实现更感兴趣。

【问题讨论】:

  • “随机”有多随机?您是否只需要一些随机检查的东西?可以通过统计测试的东西?加密强度随机性?
  • 随机性不是很重要,它甚至可以遵循某种模式,只要它不会遗漏任何数字。我想我应该将其添加到列表中,以明确不能缺少任何数字。
  • 您可以尝试将“伪随机排列”作为搜索词:想法是将这样的排列应用于固定序列 1、2、3...,以获得您的伪随机序列。分组密码是伪随机排列的一种可能来源。
  • @Spektre:OP 说“不存储数组,列出所有可能的数字”,所以这是行不通的。
  • 我对票数接近感到惊讶;这对我来说似乎是一个定义明确的问题(@rossum 的回答表明它在实践中是可以回答的)。

标签: math random range theory generated


【解决方案1】:

加密。加密是两个集合之间的一对一映射。如果这两个集合相同,则它是由加密密钥指定的排列。编写/查找将 {0, 1000} 映射到自身的加密。阅读Format Preserving Encryption (FPE) 在这里为您提供帮助。

要生成随机顺序,只需按顺序加密数字 0、1、2、...。您不需要存储它们,只需跟踪您通过列表的距离即可。

从实际的角度来看,{0, 1023} 中的数字会更容易处理,因为它是一个 10 位块大小的分组密码,您可以编写一个简单的 Feistel cipher 来生成您的数字.无论如何,您可能都想这样做,只需重新加密 1000 以上的数字——FPE 的循环行走方法。

【讨论】:

  • 如果这个答案可以包含更多信息或实际示例的链接,那就太好了。 Wikipedia 链接非常学术,并不能真正帮助那些没有前导知识并且只想了解如何解决 OP 原始问题的人。
  • 提问者说:“我对方法比实际实现更感兴趣。”这就是为什么我给出了一个高层次的“方法”答案,而不是一个详细的实施答案。
  • 这很有道理,但是您能否提供一些额外的信息?对于我们其他人? :)
【解决方案2】:

如果随机性不是主要问题,您可以使用linear congruential generator。由于当模数是素数时 LCG 不会产生最大长度序列,因此您需要选择更大的模数(下一个最高的 2 次方将是一个明显的选择)并跳过所需范围之外的任何值。

恐怕 C# 不是我的菜,但希望下面的 Python 是不言自明的。如果您想在非常小的范围内生成序列,则需要进行一些调整:

# randint(a, b) returns a random integer in the range (a..b) (inclusive)
from random import randint

def lcg_params(u, v):
    # Generate parameters for an LCG that produces a maximal length sequence
    # of numbers in the range (u..v)
    diff = v - u
    if diff < 4:
         raise ValueError("Sorry, range must be at least 4.")
    m = 2 ** diff.bit_length()              # Modulus
    a = (randint(1, (m >> 2) - 1) * 4) + 1  # Random odd integer, (a-1) divisible by 4
    c = randint(3, m) | 1                   # Any odd integer will do
    return (m, a, c, u, diff + 1)

def generate_pseudorandom_sequence(rmin, rmax):
    (m, a, c, offset, seqlength) = lcg_params(rmin, rmax)
    x = 1         # Start with a seed value of 1
    result = []   # Create empty list for output values
    for i in range(seqlength):
        # To generate numbers on the fly without storing them in an array,
        # just run the following while loop to fetch a new number
        while True:
            x = (x * a + c) % m             # Iterate LCG until we get a value in the
            if x < seqlength: break         # required range
        result.append(x + offset)           # Add this value to the list
    return result

示例:

>>> generate_pseudorandom_sequence(1, 20)
[4, 6, 8, 1, 10, 3, 12, 5, 14, 7, 16, 9, 18, 11, 20, 13, 15, 17, 19, 2]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-25
    • 2015-07-28
    相关资源
    最近更新 更多