【问题标题】:all possible length k combinations of a string in pythonpython中字符串的所有可能长度k组合
【发布时间】:2013-10-17 21:02:42
【问题描述】:

我想得到长度为 k 的字符串中所有可能的字母组合。我知道这方面有很多帖子,但我有点扭曲 k 大于字符串的长度。

这是我目前所拥有的,它很简单,如果 k

 string = 'ABCD'
 permutations = ["".join(x) for x in itertools.permutations(string, k)]

k = 4 时的结果:

 ['ABCD', 'ABDC', 'ACBD', 'ACDB', 'ADBC', 'ADCB', 'BACD', 'BADC', 'BCAD', 'BCDA', 
'BDAC','BDCA', 'CABD', 'CADB', 'CBAD', 'CBDA', 'CDAB', 'CDBA', 'DABC', 'DACB', 
'DBAC', 'DBCA', 'DCAB', 'DCBA']

这按预期工作。但是,我想要这四个字母与 k > len(string) 的所有可能组合。

我想要的一个示例答案是:

string = 'AB'
k = 4
result = ['AAA,'ABB','AAB', 'ABA','BBB', 'BAA'.......]

提前致谢。

【问题讨论】:

  • 有 4^15 个长度为 15 的字符串,由 A、B、C 和 D 组成。超过 十亿 个字符串。当然,你的电脑卡住了。 (请注意,有 15 个元素的 一万亿 个排列,这是您要求计算机计算的)
  • 你应该举例说明你想看到什么输出。
  • @nneonneo:是的,这样一来,SO 可能会在尝试处理多 GB 的 HTTP POST 时被卡住,而不仅仅是发问者的计算机被卡住 ;-)
  • @Samantha:那就问吧。不要陷入 X/Y 问题的陷阱。 (如果你真的检查每一个组合,你的内存和 CPU 时间会爆炸。有很多,更简单的方法)。
  • 您的示例似乎不对应。您在最后的示例中有'AAA',但您说正确的permutations 代码的输出中没有'AAAA'

标签: python string algorithm


【解决方案1】:

你可能想要

itertools.product(string, repeat=k)

相反。试试吧!您的描述不明确,因此无法确定。

例子:

>>> import itertools
>>> for p in itertools.product("ab", repeat=3):
...     print p
('a', 'a', 'a')
('a', 'a', 'b')
('a', 'b', 'a')
('a', 'b', 'b')
('b', 'a', 'a')
('b', 'a', 'b')
('b', 'b', 'a')
('b', 'b', 'b')

【讨论】:

  • 还要注意,您不太可能有足够的内存来制作 k=15 的列表。不过没关系,itertools 的部分意义在于生成的序列对于内存来说太大了。
【解决方案2】:

根据您的评论:

我正在尝试在一个非常大的字符串中搜索每个组合的出现次数,并查看哪个组合出现的频率最高。

还有另一种方法可以做你想做的事:

def substrings(vlarge, k):
    return (vlarge[idx:idx+k] for idx in range(len(vlarge)-k+1))

def uses_only(value, chars):
    return all(ch in chars for ch in value)

def most_common(vlarge, chars, k):
    return collections.Counter(s for s in substrings(vlarge, k) if uses_only(s, chars)).most_common(1)

然后您可以考虑使这个基本概念更有效:例如,如果您在vlarge 中遇到'x' 字符,那么您知道包含它的所有子字符串都不是'abcd' 的组合。所以你可以跳到x之后开始的子字符串:

def generate_substrings(vlarge, chars, k):
    idx = 0
    goodrange = 0
    while idx <= len(vlarge) - k:
        while goodrange < idx + k:
            if vlarge[goodrange] in chars:
                goodrange += 1
            else:
                idx = goodrange + 1
                if idx > len(vlarge) - k:
                    return
                goodrange = idx
        yield vlarge[idx:goodrange]
        idx += 1

def most_common(vlarge, chars, k):
    return collections.Counter(generate_substrings(vlarge, chars, k)).most_common(1)

与这种方法相比,“明显”的想法(遍历所有组合,计算它们作为子字符串出现的次数,并跟踪迄今为止最好的)使用更少的内存,但会是一个 很多 较慢,因为它必须在非常大的字符串上进行 很多 次传递。

如果我误解了你所说的“组合”是什么意思,也就是说如果我的uses_only 函数不正确,那么你必须相应地调整我的想法。关键是:计算你想要的形式的实际子串,因为它们的数量少于假设的正确形式的子串。

【讨论】:

    【解决方案3】:

    我的回答只是对你在做什么的理论分析。 我将用 C(k,n) 表示定义包含 n 个元素的集合中包含 k 个元素的部分的数量的二项式系数。

    假设你有一个长度为 n ∈ ℕ*k ∈ ℕ, k ⩾ n 的字符串.我会假设您的字符串中的所有字符都是不同的。
    我了解到您正在尝试构建从输入字符串中提取的 k 个字符的字符串。

    字符串字符的组合可以看作是 ⟦1, n⟧ 的排列。有 n! 个这样的排列...

    然后,当 k > n 时,事情变得更糟了……让 r = k mod np = (k - r)/ n。显然我们有:

    p ⩾ 1
    0 ⩽ r

    您的输出字符串可以分解为 p 由您的 n 个输入字符的排列组成的“完整”子字符串和一个仅由 组成的子字符串r 输入字符串的字符。

    要构建这样一个“不完整”的子字符串,您首先必须选择输入字符串的 r 个字符的子集,然后选择这些字符的排列。最后,这种可能的子串的数量 sr,n 是:

    sr,n = C(r,n).r!

    请注意,当 r = 0 时,此公式不会导致无效的全局结果,因为 C(0,n) = 1 和 0! = 1 按照惯例。

    您可以根据您的方案构建的 k-long 字符串的最终数量是:

    stot = (C(r,n).r!).(n!)p

    这个数字高得离谱

    有了 k = 4n = 2,我们有:

    stot = (C(0,4).0!).(2!)2 = 4

    result = ['ABAB', 'ABBA', 'BAAB', 'BABA']
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-06
      • 1970-01-01
      • 2019-07-24
      • 2011-11-25
      • 2021-08-12
      • 2018-10-14
      • 2016-02-07
      • 2017-11-11
      相关资源
      最近更新 更多