【问题标题】:How to find all possible ways to divide a string into n slices without recursion?如何找到所有可能的方法将字符串分成 n 片而不递归?
【发布时间】:2021-07-08 09:32:49
【问题描述】:

我需要编写一个函数,接收一个字符串和组数,然后返回所有可能的切片选项。

即对于func('hello', 3)

[['h', 'e', 'llo'], ['h', 'el', 'lo'], ['h', 'ell', 'o'], ['he', 'll', 'o'], ['he', 'l', 'lo'], ['hel', 'l', 'o']]

如何在不使用递归的情况下做到这一点?这应该只能使用循环和列表来实现。

这类似于“将球分成箱”的问题,但在这种情况下它是不同的,因为对象的顺序永远不会改变,只是切片。

这是我目前拥有的代码:

def divide_into_two(word):
    list_of_divs = []
    for i in range(1, len(word)):
        list_of_divs.append([word[0:i], word[i:len(word)]])

    return list_of_divs

它只是把一个词分成两组。我想我们需要某种内部循环来继续划分它,以防它有更多的组,但我不知道该怎么做。

【问题讨论】:

  • 构造总和为N = len(your_str)的所有正数元组。毫无疑问,这已经解决了。
  • 有趣的谜题。要获得有关 stackoverflow 的帮助,强烈建议您解释(通过编辑您的问题)您到目前为止所尝试的内容。
  • 蒂姆,我确信这已经解决了。构建元组听起来更像是一个将球放入垃圾箱的问题,但对象的顺序必须保持不变。例如 ["e", "lmon"] 不是 "lemon" 的有效除法。 @timgeb
  • 如果您有递归解决方案,您可以使用堆栈将其机械地转换为迭代解决方案。
  • @kanyeeast 元组方法不会打乱字符串。如果您正在构建所有总和为len(your_str) 的元组,那么您将得到类似(3, 1, 1) 的元组,它对应于['hel', 'l', 'o']。或者(2, 2, 1),对应['he', 'll', 'o']

标签: python list loops for-loop


【解决方案1】:

使用itertools.combinations 选择要剪切字符串的索引:

from itertools import combinations

def func(s, n):
    return [[s[i:j] for i, j in zip([None, *cuts], [*cuts, None])]
            for cuts in combinations(range(1, len(s)), n-1)]

func('hello', 3) 的结果:

[['h', 'e', 'llo'], ['h', 'el', 'lo'], ['h', 'ell', 'o'], ['he', 'l', 'lo'], ['he', 'll', 'o'], ['hel', 'l', 'o']]

另一种解决方案,从所有单片分割(即,整个字符串)开始,然后计算两片分割,然后是三片分割,等等。通过始终将最后一片分割成两部分来完成允许所需的剩余拆分数量的方法:

def func(s, n):
    divs = [[s]]
    for i in range(n-1):
        divs = [[*keep, last[:j], last[j:]]
                for *keep, last in divs
                for j in range(1, len(last)-n+i+2)]
    return divs

【讨论】:

  • 是的,我只是忘记了这些部门。非常感谢。你认为有可能在简单的 Python 中实现类似“组合”的功能吗?
  • @kanyeeast 没有比使用现有函数更简单的 Python 了 :-)。 its documentation 中有一个可能的实现,尽管这可能比这里需要的更通用。如果我必须在没有 itertools 的情况下这样做,我可能会编写一个小递归函数。
  • @kanyeeast 现在添加了第二个解决方案,迭代而不是递归,因为递归会让我感到无聊:-)
【解决方案2】:

您可以使用more itertools

from more_itertools import partitions

def divide_into_parts(word, parts):
    result = []
    for p in partitions(word):
        if len(p) == parts:
            result.append([''.join(s) for s in p])
    return result

结果

divide_into_parts('hello', 3)

[['h', 'e', 'llo'],
 ['h', 'el', 'lo'],
 ['h', 'ell', 'o'],
 ['he', 'l', 'lo'],
 ['he', 'll', 'o'],
 ['hel', 'l', 'o']]

【讨论】:

  • 生成所有分区只是为了扔掉大部分不是很有效。最好考虑可能的切片位置的组合,仅使用itertools
【解决方案3】:

这是一个可能的解决方案:

from itertools import combinations

def slicings(s, g):
    for c in combinations(range(1, len(s)), g - 1):
        yield [s[start:end] for start, end in zip((0,) + c, c + (len(s),))]

您现在可以使用切片生成器做任何您想做的事情:

for slicing in slicings('hello', 3):
    print(slicing)
['h', 'e', 'llo']
['h', 'el', 'lo']
['h', 'ell', 'o']
['he', 'l', 'lo']
['he', 'll', 'o']
['hel', 'l', 'o']

在这些情况下,最好根据需要生成内容(使用 yield 而不是 return),因为根据您的具体情况,结果可能呈指数级增长。

【讨论】:

    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 2011-05-15
    相关资源
    最近更新 更多