第22题:括号生成
1.题目链接
[https://leetcode-cn.com/problems/generate-parentheses/solution/]
2.题目内容
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
3.解题思路
本题目的是将括号随机组合,并且满足括号为有效括号,即"()",思路如下:
(1)建立字典dict = {1: “(”, -1: “)”},将前括号"(“标记为1,后括号”)"标记为-1;
(2)先采用暴力方法遍历所有排列组合的可能性,比如当n为3时,所有的可能性如下所示:
(1, -1, 1, -1, -1, 1)
(1, -1, -1, -1, 1, 1)
(-1, 1, 1, -1, -1, 1)
(-1, 1, -1, 1, 1, -1)
(-1, 1, -1, -1, 1, 1)
(-1, -1, 1, 1, 1, -1)
(1, -1, 1, -1, 1, -1)
(-1, 1, 1, 1, -1, -1)
(-1, -1, 1, -1, 1, 1)
(1, 1, -1, -1, 1, -1)
(1, -1, -1, 1, -1, 1)
(-1, 1, 1, -1, 1, -1)
(1, 1, 1, -1, -1, -1)
(-1, 1, -1, 1, -1, 1)
(-1, -1, -1, 1, 1, 1)
(-1, -1, 1, 1, -1, 1)
(1, -1, 1, 1, -1, -1)
(1, -1, -1, 1, 1, -1)
(1, 1, -1, 1, -1, -1)
(1, 1, -1, -1, -1, 1)
(3)对每种可能性的前1~n*2项分别求和,需要满足求的每次和都大于等于0,比如(1, 1, -1, 1, -1, -1),每次求和的值1(1,),2(1+1),1(1+1-1),2(1+1-1+1),1(1+1-1+1-1),0(1+1-1+1-1-1),每次求和都大于等于0,满足题目的意思。
(4)用字典将1替换成“(”,-1替换成“)”
4.代码实现
# 自己解法 (存在问题,当n较大时,运行时间过长)
#(甲)
import itertools
class Solution:
def generateParenthesis(n):
"""
:type n: int
:rtype: List[str]
"""
src = [1]* n
for i in range(int(n)):
src.append(-1)
a = list(set(itertools.permutations(src,len(src))))
vf = []
for i in range(int(len(a))):
for j in range(n*2):
if sum(a[i][0:j+1]) < 0 & j+1 < n*2:
break
elif j+1 == n*2:
b = a[i]
rep = ["(" if x == 1 else ")" for x in b]
f = "".join(rep)
vf.append(f)
return vf
网上最优解法
方法一:暴力法
思路
我们可以生成所有 2^{2n}个 ‘(’ 和 ‘)’ 字符构成的序列。然后,我们将检查每一个是否有效。
算法
为了生成所有序列,我们使用递归。长度为 n 的序列就是 ‘(’ 加上所有长度为 n-1 的序列,以及 ‘)’ 加上所有长度为 n-1 的序列。
为了检查序列是否为有效的,我们会跟踪平衡,也就是左括号的数量减去右括号的数量的净值。如果这个值始终小于零或者不以零结束,该序列就是无效的,否则它是有效的。
class Solution(object):
def generateParenthesis(self, n):
def generate(A = []):
if len(A) == 2*n:
if valid(A):
ans.append("".join(A)) # 将判断后有效的list中()连接在一起形成str
else:
A.append('(') # 构造A的生成过程,在A后面加上"("
generate(A) # 做一次判断
A.pop() # 删除A最后一个元素
A.append(')') # 在A后面加上")"
generate(A) # 做一次判断
A.pop() # 删掉A最后一个元素
def valid(A): # 对于A的有效性判断,有效括号
bal = 0 # 假如前1~2n项中之和有为负,则返回False,
for c in A: # 否则返回 bal == 0
if c == '(': bal += 1
else: bal -= 1
if bal < 0: return False
return bal == 0
ans = []
generate()
return ans
方法二:回溯法
思路和算法
只有在我们知道序列仍然保持有效时才添加 ‘(’ or ‘)’,而不是像方法一那样每次添加。我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,
如果我们还剩一个位置,我们可以开始放一个左括号。 如果它不超过左括号的数量,我们可以放一个右括号。
class Solution(object):
def generateParenthesis(self, N):
ans = []
def backtrack(S = '', left = 0, right = 0):
if len(S) == 2 * N:
ans.append(S)
return
if left < N:
backtrack(S+'(', left+1, right) # 先加"("再加")",保证有效括号
if right < left:
backtrack(S+')', left, right+1)
backtrack()
return ans
5. 涉及知识点
(1)list(set(itertools.permutations(src,len(src)))),itertools包可以生成数列的所有种可能。
(2)循环做break跳出循环时,注意break的位置。