我试图在Python中的“Programming Interviews Exposed”中实现该算法,如下所示,但它似乎不起作用(第2版第99页):
这个想法是生成一个字符串的所有组合(而不是排列),这样如果你输入“wxyz”,你就会得到“w,wx,wxy,wxyz,wxz,wy,wyz,wz ......”如果显示wz,那么zw无效。
def doCombine(strng, out, length, level, start):
for i in range(start, length):
out.append(strng[i])
print out
if (i < length - 1):
doCombine(strng, out, length, level +1, i + 1)
out = out[:-1]
x = list()
target = "wxyz"
print doCombine(target, x, len(target), 0, 0)
这可能有什么不妥之处?我得到相对垃圾输出。
答案 0 :(得分:3)
在当前代码中,尝试将行out = out[:-1]
更改为del out[-1]
。这两个导致out
删除了最后一项,但在当前代码中out
被重新分配而不是使用相同的列表。这导致字符永远不会从原始列表中删除,这显然会使输出显着混乱。
进行更改后,输出结果如下:
>>> print doCombine(target, x, len(target), 0, 0)
['w']
['w', 'x']
['w', 'x', 'y']
['w', 'x', 'y', 'z']
['w', 'x', 'z']
['w', 'y']
['w', 'y', 'z']
['w', 'z']
['x']
['x', 'y']
['x', 'y', 'z']
['x', 'z']
['y']
['y', 'z']
['z']
None
答案 1 :(得分:2)
请参阅itertools模块中的combination()函数。
答案 2 :(得分:1)
我使用递归生成器重写了这个组合函数。输出是一个迭代器。
def combine(s):
length = len(s)
def gen(start, prepending=[]): #recursive generator
if start == length-1:
yield prepending + [s[start]]
else:
for i in range(start,length):
current = prepending + [s[i]] #save the current list for reusing
yield current
for els in gen(i+1,current):
yield els
for v in gen(0):
yield v
s = "wxyz"
for v in combine(s):
print(v)
立刻理解起来并不容易。
在联合生成器中使用相同的技术:Conjoin function made in functional style。
另外,我在尝试理解它的工作原理时稍微重构了一下你的函数。 我会把它放在那些可能有兴趣放松理解的人身上。
def combine(s):
out = []
length = len(s)
def loc(start):
for i in range(start, length):
out.append(s[i])
print out
if (i < length-1):
loc(i+1)
del out[-1]
loc(0)
我进行了一些效率计算。
使用来自out
的附加和删除的代码(原始海报的略微修改的代码用作生成器)比我在此答案中提供的代码快一点(我认为这是因为我使用过每次迭代prepending + [s[i]]
在内存中创建一个新列表。同一列表上的附加和删除变得更快。)
详细信息: https://ideone.com/V3WIM
答案 3 :(得分:0)
行out.append(strng[i])
与描述的算法不匹配。你不想追加,你想要设置[level] = strng [i]