題目描述:
給出 n 代表生成括號的對數(shù),請你寫出一個函數(shù),使其能夠生成所有可能的并且有效的括號組合。
例如,給出 n = 3,生成結(jié)果為:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
我的方法:
一種思路是列出所有可能性,排除其中不合法的組合。這種方法的時間復雜度高達O()。這自然不是一種經(jīng)濟的方法。
如果仔細考察結(jié)果,我們能夠發(fā)現(xiàn)合法的結(jié)果符合以下特征:
- 最左邊一定是左括號“(”,最右邊的一定是右括號“)”。
- 都是由3個左括號、3個右括號構(gòu)成。
- 也許可以用遞歸,合法字符串剔除兩個最內(nèi)層的括號之后,剩余的部分依然合法。
- 每個合法字符串必然至少有一對最內(nèi)層的括號,當然也可以有嵌套的括號。
最終是使用遞歸方法來處理的。正如之前所述,遞歸需要考慮移動和終止條件兩個因素。
中文網(wǎng)站居然報錯(而且顯然是網(wǎng)站自身問題導致的報錯),只好去leetcode英文網(wǎng)站來提交了。效果一般,但總算沒有超時。Runtime: 88 ms, faster than 5.64% of Python online submissions for Generate Parentheses.Memory Usage: 12.2 MB, less than 5.02% of Python online submissions for Generate Parentheses.
class Solution(object):
def generateParenthesis(self, n):
"""
:type n: int
:rtype: List[str]
"""
if n==1:
return ["()"]
# n對括號可以認為是n-1和1對括號的組合
# 其中這1對括號可以看成是一個整體,同時移動
ans=[]
for ele in self.generateParenthesis(n-1):
for i,v in enumerate(ele):
tmp=ele[:i]+'()'+ele[i:]
if tmp not in ans:
ans.append(tmp)
return ans
別人的方法:
用的是回溯,這個方法算是新技能,直觀上不太容易理解。回溯就是通過不同的嘗試來生成問題的解。有點類似于窮舉,但是和窮舉不同的是回溯會“剪枝”,意思是對已知錯誤的結(jié)果沒必要再繼續(xù)嘗試了。
回溯的步驟如下:
- 定義合法的搜索結(jié)果:左括號的數(shù)量等于n,并且右括號的數(shù)量等于n。凡是合法的搜索結(jié)果,便加入到數(shù)組ans中。
- 定義括號生成的路徑,也可以理解成是樹生成的路徑。只有在兩種情況下,才可能生成合法的樹。
- 一種生長路徑是:左括號的數(shù)量l小于n時,可以對字符串s增加左括號,每次增加一個左括號。
- 另一種生長路徑是:當左括號的數(shù)量l>右括號數(shù)量r時,可以對字符串s增加右括號,每次增加一個右括號。
- 通過遞歸調(diào)用,這兩種生長路徑可能會相互以不同的順序穿插,從而生成不同的合法字符串s。
效果有所提升:執(zhí)行用時 : 36 ms, 在Generate Parentheses的Python提交中擊敗了33.55% 的用戶。內(nèi)存消耗 : 12.2 MB, 在Generate Parentheses的Python提交中擊敗了0.00% 的用戶
class Solution(object):
def generateParenthesis(self, N):
res=[]
def backtrack(s,n,l,r):
if l==n and r==n:
res.append(s)
return
if l<n:
# 注意:這里是調(diào)用,而無需返回。
# 每一次調(diào)用,都可能生成合法結(jié)果
backtrack(s+'(',n,l+1,r)
if l>r:
backtrack(s+')',n,l,r+1)
# 注意backtrack()并不返回任何值,只是改變了變量res的值
backtrack('',N,0,0)
# 最終輸出res即可
return res