【问题标题】:Generate Sequence Without Permutations生成没有排列的序列
【发布时间】:2013-12-11 14:21:59
【问题描述】:

我使用整数中的两位数字来表示一个元素。 IE。 3345512 代表四个元素 [3,34,55,12]。接下来,我重复地将一个整数加到一个整数上以获得另一个元素序列。当生成这样的序列时,我得到相同序列的排列,即3341255 = [3,34,12,55],在我的情况下,它相当于数字3345512 = [3,34,55,12]。所以我想避免我已经遇到的序列的排列。我不想存储这些数字,因为它们变得非常大(10^30 等等)。我尝试使用布隆过滤器,但它无法处理元素的数量。是否有一个简单的解决方案来生成没有排列的序列?

[编辑] 这是一个很小的 ​​python 脚本,应该可以工作。为了更好地理解,我使用if s[idx] == 9: 的单个数字而不是if s[idx] == 99: 如果您有更简单的解决方案,我会接受它作为答案。

import time
s = [1]
while True:
    idx = 0
    while not idx+1 == len(s) and not s[idx] < s[idx+1]:
        s[idx] = 1
        idx += 1
    if s[idx] == 9:
        s[idx] = 1
        s.append(1)
    else:
        s[idx] += 1
    print repr(s)
    time.sleep(0.7)

【问题讨论】:

  • 如果您想避免重复序列,它们是彼此的排列,请仅选择其中一种排列作为代表,例如元素形成非递减序列的排列。
  • Chill 的想法很好,从 0 开始计数。否则,您可能会错过一些序列。例如,如果您从5050 开始计数,即使您从未遇到过4951,也会跳过5149
  • 你想要combinations而不是排列。
  • @Jim:“计算多子集”部分似乎很合适,尽管没有关于如何实现它的建议。

标签: algorithm math permutation


【解决方案1】:

您要求的是组合而不是排列。看起来您正在尝试从 100 个列表中获取 4 个项目的唯一组合。也就是说,您的可能值是 0099

您可以使用嵌套循环生成所有组合,如下所示:

for (i = 0 to 96)
    for (j = i + 1 to 97)
        for (k = j + 1 to 98)
            for (l = k + 1 to 99)
                write i, j, k, l

这保证您不会得到相同的组合。

您还会注意到在生成的组合中:

i < j < k < l

如果你让你的序列总是满足那个不等式,那么你就不会得到重复的组合。

因此,您的示例 3345512 将永远不会生成。应该是3123455

鉴于,当您从3123499 递增时,您不会转到3123500,而是转到3123536。基本上,如果溢出一个位置,则增加下一个位置,原始位置变为(下一个位置 + 1)。所以3999999 增加到4050607

显然,您不能使用简单的整数增量来做到这一点。我建议使用 4 字节的值和一点逻辑。

这是另一种方法。

假设您的字母表只有 4 个字符,[0, 1, 2, 3]。共有 16 种可能的独特组合。您想要两个项目的独特组合。

现在,考虑一个 4 位数字,它可以保存 0 到 15 的值。您可以将该数字映射到唯一的组合,以便数字 3(0011 二进制)对应于组合 0、1。即,位设置 0 并设置位 1。应该清楚的是,设置了 2 位的数字对应于唯一的 2 字符组合。对于 4 个项目的字母表中的 2 个组合,我们有:

0, 1  (0011)
0, 2  (0101)
0, 3  (1001)
1, 2  (0110)
1, 3  (1010)
2, 3  (1100)

有了这个,你可以增加一个整数,看看它是否设置了两个位,然后从设置的位转换为你的字母表中的字符。

您可以从一组 100 个字符中选择 4 个组合来执行完全相同的操作。使用 100 位数字有点困难,但并非不可能。由于您只是在递增,因此可以使用一对 64 位数字来完成。

确定设置了多少位很容易以幼稚的方式进行。 Bit Twiddling Hacks 页面显示了几种更快的方法。

有几种方法可以解决这个问题,所有这些方法都可以参数化以从 n 个项目的列表中选择唯一的 k 组合。

【讨论】:

  • 我不想像这样对问题进行硬编码,因为我不知道我需要多少个循环。虽然这看起来是一个非常简单且很好的解决方案。
  • @phobic:这些循环只是展示了如何生成四个的组合。很容易想出一个通用方法,它可以从 m 列表中生成 n 项的组合。
  • 如果你能想出比我的脚本更具可读性的东西,我会接受你的回答。也许我可以使用递归和生成器来模拟无限嵌套的 for 循环。我想不出别的了。
  • @phobic:我认为您发布的脚本与我的想法相似。我不是 Python 程序员,所以我不会尝试用 Python 编写代码。当我讨论如何递增时,我在上面描述了我的算法。
  • @phobic 这是我用 C++ 编写的一个算法,它使用这种精确的方法来解决这个精确的问题。也许它会有一些用处。 Here is a link to my explanation of the algorithm
【解决方案2】:

要检查给定的序列是否已经生成并且可以跳过,您应该生成当前序列的“先前”排列,如果从零开始计数将生成,并将其与起始编号进行比较。

您可以通过以下方式找到此排列:

如果数字按递增顺序排列 - 例如 [3] [4] [5] [6] - 您可以停止,因为这些数字没有更小的排列。

如果序列有一些非递增部分 - 例如 [3] [5] [4] [8] [6] [7] [8] [9]。这个序列有两个不递增的部分。 5-4 和 8-6。

找到最后一个大于它的后继的数字。这是前 8 个。

[3] [5] [4] [8] [6] [7] [8] [9]

找出 8 后面最大的数字,实际上它更小。现在是 7 点。

[3] [5] [4] [8] [6] [7] [8] [9]

将 7 移到 8 的位置,其余所有数字按降序排列。

[3] [5] [4] [7] [9] [8] [8] [6]

现在如果这个序列小于起始数字 - 你知道它还没有生成。否则你可以跳过它。

【讨论】:

  • 抱歉,我没听懂。您能否明确说明重新排序的目的是什么,以及您如何知道您的算法确实实现了它?也许您可以简单地对序列进行排序,而不是使用您的算法来获得“最小”排列并将其与当前序列进行比较?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 2013-10-30
  • 2013-04-22
  • 2013-10-01
相关资源
最近更新 更多