我需要打印不同版本的打印有效标签“<”和“>”给出标签出现的次数,下面是使用递归的python中的解决方案。
def genBrackets(c):
def genBracketsHelper(r,l,currentString):
if l > r or r == -1 or l == -1:
return
if r == l and r == 0:
print currentString
genBracketsHelper(r,l-1, currentString + '<')
genBracketsHelper(r-1,l, currentString + '>')
return
genBracketsHelper(c, c, '')
#display options with 4 tags
genBrackets(4)
我很难理解这一点,并希望尝试将其转换为迭代版本,但我没有取得任何成功。
根据这个帖子:Can every recursion be converted into iteration? - 它看起来应该是可能的,唯一的例外似乎是Ackermann函数。
如果有人知道如何查看Eclipse中维护的“堆栈” - 那也将不胜感激。
PS。这不是一个功课问题 - 我只是想更好地理解递归到迭代转换。
由Matthieu M编辑。输出示例,以便更好地实现可视化:
>>> genBrackets(3)
<<<>>>
<<><>>
<<>><>
<><<>>
<><><>
答案 0 :(得分:4)
我尝试保持与代码基本相同的结构,但是使用显式堆栈而不是函数调用genBracketsHelper
:
def genBrackets(c=1):
# genBracketsStack is a list of tuples, each of which
# represents the arguments to a call of genBracketsHelper
# Push the initial call onto the stack:
genBracketsStack = [(c, c, '')]
# This loop replaces genBracketsHelper itself
while genBracketsStack != []:
# Get the current arguments (now from the stack)
(r, l, currentString) = genBracketsStack.pop()
# Basically same logic as before
if l > r or r == -1 or l == -1:
continue # Acts like return
if r == l and r == 0:
print currentString
# Recursive calls are now pushes onto the stack
genBracketsStack.append((r-1,l, currentString + '>'))
genBracketsStack.append((r,l-1, currentString + '<'))
# This is kept explicit since you had an explicit return before
continue
genBrackets(4)
请注意,我使用的转换依赖于函数末尾的所有递归调用;如果不是这样的话代码会更复杂。
答案 1 :(得分:2)
你没有堆叠就问过这个问题。
此算法遍历整个解决方案空间,因此它比原始版本做了更多的工作,但它基本上是相同的概念:
由于每个路径都是一系列二元决策,因此路径对应于0到2 **(c * 2)-1之间整数的二进制表示。
所以:只需遍历这些数字,看看二进制表示是否对应于平衡字符串。 :)
def isValid(string):
"""
True if and only if the string is balanced.
"""
count = { '<': 0, '>':0 }
for char in string:
count[char] += 1
if count['>'] > count['<']:
return False # premature closure
if count['<'] != count['>']:
return False # unbalanced
else:
return True
def genBrackets(c):
"""
Generate every possible combination and test each one.
"""
for i in range(0, 2**(c*2)):
candidate = bin(i)[2:].zfill(8).replace('0','<').replace('1','>')
if isValid(candidate):
print candidate
答案 2 :(得分:1)
通常,递归会创建一个调用树,根是原始调用,而叶子是不递归的调用。
退化情况是每个调用仅执行另一个调用,在这种情况下,树退化为一个简单列表。然后通过使用堆栈简单地实现向迭代的转换,如@Jeremiah所示。
在更一般的情况下,就像这里一样,当每次通话比一次通话执行更多(严格)时。你获得了一棵真正的树,因此有几种方法可以遍历它。
如果使用队列而不是堆栈,则执行广度优先遍历。 @Jeremiah提出了一个我不知道名字的遍历。典型的“递归”顺序通常是深度优先遍历。
典型递归的主要优点是堆栈的长度不会增长太多,所以你应该首先瞄准深度优先......如果复杂性没有压倒你:)
我建议首先编写一个树的深度优先遍历,一旦完成,将其调整到你的算法应该相当简单。
编辑:由于我有一段时间,我编写了Python Tree Traversal,这是一个典型的例子:
class Node:
def __init__(self, el, children):
self.element = el
self.children = children
def __repr__(self):
return 'Node(' + str(self.element) + ', ' + str(self.children) + ')'
def depthFirstRec(node):
print node.element
for c in node.children: depthFirstRec(c)
def depthFirstIter(node):
stack = [([node,], 0), ]
while stack != []:
children, index = stack.pop()
if index >= len(children): continue
node = children[index]
print node.element
stack.append((children, index+1))
stack.append((node.children, 0))
请注意,由于需要记住我们当前访问的孩子的索引,因此堆栈管理稍微复杂。
按照深度优先顺序对算法进行调整:
def generateBrackets(c):
# stack is a list of pairs children/index
stack = [([(c,c,''),], 0), ]
while stack != []:
children, index = stack.pop()
if index >= len(children): continue # no more child to visit at this level
stack.append((children, index+1)) # register next child at this level
l, r, current = children[index]
if r == 0 and l == 0: print current
# create the list of children of this node
# (bypass if we are already unbalanced)
if l > r: continue
newChildren = []
if l != 0: newChildren.append((l-1, r, current + '<'))
if r != 0: newChildren.append((l, r-1, current + '>'))
stack.append((newChildren, 0))
我刚刚意识到存储索引有点“太”复杂,因为我从不回访。因此,简单的解决方案在于删除我不再需要的列表元素,将列表视为队列(实际上,堆栈就足够了)!
这适用于最小转换。
def generateBrackets2(c):
# stack is a list of queues of children
stack = [[(c,c,''),], ]
while stack != []:
children = stack.pop()
if children == []: continue # no more child to visit at this level
stack.append(children[1:]) # register next child at this level
l, r, current = children[0]
if r == 0 and l == 0: print current
# create the list of children of this node
# (bypass if we are already unbalanced)
if l > r: continue
newChildren = []
if l != 0: newChildren.append((l-1, r, current + '<'))
if r != 0: newChildren.append((l, r-1, current + '>'))
stack.append(newChildren)
答案 3 :(得分:0)
是
def genBrackets(c):
stack = [(c, c, '')]
while stack:
right, left, currentString = stack.pop()
if left > right or right == -1 or left == -1:
pass
elif right == left and right == 0:
print currentString
else:
stack.append((right, left-1, currentString + '<'))
stack.append((right-1, left, currentString + '>'))
输出顺序不同,但结果应该相同。