【问题标题】:Get all possible str partitions of any length获取所有可能的任意长度的 str 分区
【发布时间】:2019-02-09 13:10:37
【问题描述】:

我想找到一个 str 的所有可能分区,没有空 strs 并且必须包含任何 char(不应包含原始 str)

例如:

s = '1234'

partitions(s)  # -> [['1', '2', '3', '4'], ['1', '2', '34'], ['1', '23', '4']
               #     ['12', '3', '4'], ['12', '34'], ['1', '234'], ['123', '4']]
               # should not contain ['1234']

编辑:可以是任何顺序

为什么我的问题不是重复的:

我不想要以下排列:

from itertools import permutations

s = '1234'
permutations(s) # returns ['1', '2', '3', '4'], ['1', '2', '4', '3']...

但我希望将字符串分割成多个长度(请查看第一个代码)

谢谢!

【问题讨论】:

标签: python arrays string python-3.x


【解决方案1】:

您可以定义递归(生成器)函数。这个想法是:将所有长度的字符串的前缀与剩余字符串的所有分区组合起来。

def partitions(s):
    if len(s) > 0:
        for i in range(1, len(s)+1):
            first, rest = s[:i], s[i:]
            for p in partitions(rest):
                yield [first] + p
    else:
        yield []

partitions("1234") 的结果:

['1', '2', '3', '4']
['1', '2', '34']
['1', '23', '4']
['1', '234']
['12', '3', '4']
['12', '34']
['123', '4']
['1234']

请注意,此确实包含['1234'],但之后可以轻松过滤,例如作为print([p for p in partitions("1234") if len(p) > 1]),或者您可以在list 中收集结果,然后在最后一个元素中收集pop。将此直接添加到递归函数会更复杂,因为除了顶级调用之外的每个调用应该返回那个“完整”分区。

【讨论】:

  • 它有效,谢谢,但你知道如何删除原始 str 吗?
  • @Srivaths 见最后一段。之后删除它似乎比调整算法要简单得多。
  • 带有len(sublist) == 1 的子列表将始终最后生成,因此您不必使用新的列表理解遍历整个事物以将其过滤掉。你可以做res = list(partitions); res.pop()。 +1
  • @Ev.Kounis 只是想添加这个,但话又说回来,这只在列表中收集时才有效,这有其自身的缺点。
  • 如果我没记错的话,列表的长度由 2**(len(string)-1)-1 给出,因此将结果转换为列表对 resonable-sized 输入,但可以。
【解决方案2】:

一个想法可能如下。给定一个字符串“1234”,您可以对字符串进行分区,计算子字符串的位置。

import itertools

s="1234"

possibilities = []

for i in range(1,len(s)):

    comb = itertools.combinations(range(1,len(s)), i)

    possibilities+= [[s[0:c[0]]] + [s[c[i]:c[i+1]] for i in range(len(c)-1)] + [s[c[-1]:]] for c in comb]

输出

#[['1', '234'], ['12', '34'], ['123', '4'], ['1', '2', '34'], ['1', '23', '4'], ['12', '3', '4'], ['1', '2', '3', '4']]

此解决方案的输出中不包含 ['1234'](这是因为主循环从 1 开始,而不是从 0 开始)。

只是一个脚注。
不包括原字符串的字符串分割方式数为

这个解决方案所基于的想法是这样的。根据上面的公式生成它们中的每一个。数量很大,不可能存在多项式时间算法(至少你要生成输出的每个元素,所以Ω(2^n)是一般问题的下界)。

【讨论】:

    【解决方案3】:

    使用this SO question 中的代码列出所有子字符串(移植到python 3),然后删除主字符串。然后创建所有排列并仅过滤允许的排列。

    import itertools
    
    
    def get_all_substrings(input_string):
        length = len(input_string)
        return [input_string[i:j+1] for i in range(length) for j in range(i,length)]
    
    
    def filter_func(string, iterable):
        """ Leave only permutations that contain all letters from the string and have the same char count. """
        all_chars = ''.join(iterable)
        return True if len(all_chars) == len(string) and all(char in all_chars for char in string) else False
    
    
    s = '1234'
    partitions = get_all_substrings(s)
    partitions.remove(s)  # remove '1234' (results should be only substrings not equal to the original string)
    
    results = []
    # create all permutations of all substrings, for all sub-lengths of the string length (1, 2, 3...)
    for i in range(len(s)):
        permutations = list(itertools.permutations(partitions, i + 1))
        accepted_permutations = tuple(filter(lambda p: filter_func(s, p), permutations))  # filter out unwanted permutations
        results += accepted_permutations
    
    res = list(set(tuple(sorted(l)) for l in results))  # filter out duplicates with different order
    print(res)
    

    这不如上面的递归解决方案好,但我已经装箱了,所以发布它:D 编辑:彻底修改了问题。

    【讨论】:

      猜你喜欢
      • 2018-07-02
      • 2021-02-22
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多