我正在用leetcode解决生成括号问题。如果我使用以下代码(将其作为要添加的列表):
这里f是前括号的计数器,b是后括号的计数器。
def generateParenthesis(n: int) -> List[str]:
def recursion(f, b, cur=[]):
if len(cur)==(n*2):
a ="".join(cur)
output.append(a)
return
if f:
cur.append("(")
recursion(f-1,b, cur)
if b:
cur.append(")")
recursion(f,b-1, cur)
output = []
f = n
b = n
recursion(f, b, cur)
return output
运行上述解决方案时,我得到的输出与n = 3一样:
[“(((()))”]
如果不是将其追加到列表中,而是将cur作为字符串,并在其上加上“(”),即可得到正确的答案。
def generateParenthesis(n: int) -> List[str]:
def recursion(f, b, cur=""):
if b < f or b<0 or f<0:
return
if len(cur)==n*2:
output.append(cur)
return
if f:
recursion(f-1,b, cur+"(")
if b:
recursion(f,b-1, cur+")")
output = []
f = n
b = n
recursion(f, b)
return output
这将产生当前输出,即:
[“(((()))”,“(()())”,“(())()”,“()(())”,“()()()”] < / p>
我知道字符串是不可变的,所以在字符串上加“(”就是O(N)。我只是想避免这种情况。任何人都可以帮助我了解这里发生的事情以及是否/如何使用其中的第一个代码正确的方法。我认为这与在每次递归中使用单独的列表(名为cur的变量)有关。
答案 0 :(得分:1)
首先,我不喜欢-> List[str]:
和recursion(f, b, cur)
的语法,因为在代码中未定义List,在该区域中也未定义cur。
现在让我们在第一部分中查看您的代码。
def generateParenthesis(n: int) -> List[str]:
def recursion(f, b, cur=[]):
if len(cur)==(n*2):
a ="".join(cur)
output.append(a)
return
if f:
cur.append("(")
recursion(f-1,b, cur)
if b:
cur.append(")")
recursion(f,b-1, cur)
output = []
f = n
b = n
recursion(f, b, cur)
return output
通过引用将变量cur
传递到递归中。这意味着,所有被调用的递归都共享相同的cur
变量。因此,在执行过程中,一旦生成"((()))"
,其他递归仍将增加cur
的长度,从而使"((()))"
是唯一的输出。所以如果你。将条件更改为if len(cur) >= n*2
,您将获得以下输出。
['(((()))','(((())))','(((()))))','(((())))))']
要使代码正常工作,一种幼稚的方法是每次调用递归时都创建一个新列表。例如,recursion(f-1, b, deepcopy(cur))
,其中deepcopy
是from copy import deepcopy
。但我相信在这种情况下,您宁愿使用不可变的字符串。
另一方面,您也可以将列表作为堆栈查看。在每个递归调用中,都将附加一个括号,这表示您在堆栈中推一个括号。因此,您还应该在递归调用之后弹出插入的括号。尽管在这种情况下,应使用您以前的检查条件。
由于Python的list
与C ++的vector
类似,因此我们只需维护最后一个元素的索引即可,而不是实际弹出。修改后的代码应为
def generateParenthesis(n):
def recursion(f, b, cur=[None] * (2*n), idx= 0):
if b < f or b<0 or f<0:
return
if idx >= (n*2):
a ="".join(cur)
output.append(a)
return
if f:
cur[idx] = "("
recursion(f-1,b, cur, idx + 1)
if b:
cur[idx] = ")"
recursion(f,b-1, cur, idx + 1)
output = []
f = n
b = n
recursion(f, b)
return output
让我们做print(generateParenthesis(3))
,我们得到
['(((()))','(()())','(())()','()(())','()()()'] < / p>
好。
PS:Python没有本地linkedlist
,但有本地deque
(https://docs.python.org/3/library/collections.html#collections.deque),当需要更复杂的推入和弹出操作时,可以使用此数据结构。
答案 1 :(得分:1)
我知道字符串是不可变的,因此在字符串上加上“(”是O(N)。 只是想避免这种情况。
但是有趣的是,您的字符串解决方案比@Tony基于列表的可变解决方案要快25%!至少以我的时间generateParenthesis(13)
。
下面是我基于字符串的解决方案-比@Tony慢15%左右,但没有副作用,并且可以转换为列表(甚至更慢)无危险默认值的基于解决方案的解决方案。即您可以将内部递归函数移至其自己的顶级函数,并且仍然可以使用:
def parenthesis(n):
def parenthesis_recursive(k, f, b, current=""):
if not b >= f >= 0 <= b:
return []
if len(current) == k:
return [current]
return parenthesis_recursive(k, f - 1, b, current + "(") + parenthesis_recursive(k, f, b - 1, current + ")")
return parenthesis_recursive(n * 2, n, n)
print(parenthesis(3))