(day56:P50)
目录
题目:
题目分析:
解题思路:
解法一:暴力解法(递归)
代码实现
✏代码注释
解法二:回溯法
代码实现
✏代码注释
数字 n
代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。(1 <= n <= 8)
⭐示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
⭐示例 2:
输入:n = 1
输出:["()"]
题目所说的有效括号就和我们平常使用括号的方式一样,“()”是有效的,“)(”是无效的。那么,有人认为“(())”这样的形式是无效的括号,如果你也再考虑它是否是有效括号,那可能你将是下一个马丁。
因为生成的括号只有一种也就是小括号,那么我们可以先生成所有可能的括号组合,接着再判断生成的括号是否是有效的形式。
对于如何生成全部可能的括号组合,我们可以使用递归来实现。
生成长度为n的括号组合就在长度为n-1的括号组合后添加“(” 或 “)”。
对于判断括号是否有效,我们可以使用一个标记变量balance来判断生成括号是否有效。
balance代表左括号的数量 - 右括号的数量
当balance = 0
生成括号有效
当balance != 0
生成括号无效
那么可能会有疑问,对于这样的括号组合 “)()()(”,“())()(” balance的值为0,但是它却不是有效的,那么不应该再添加其他条件来判断是否有效吗?
我们当然可以在添加其他条件来判断生成括号是否有效,比如使用栈来匹配看是否有右括号出现在左括号前,但是我们大可不必这么做。
我们只需要在遍历生成的括号组合时,遇到左括号就 +1,遇到右括号就 -1,接着判断balance是否<0,如果小于0,说明有单独右括号出现在左括号前,那么括号无效
def generateParenthesis(n):
def generate(lst):
if len(lst) == 2 * n:
if valid(lst):
result.append("".join(lst))
else:
lst.append('(')
generate(lst)
lst.pop()
lst.append(')')
generate(lst)
lst.pop()
def valid(lst):
balance = 0
for item in lst:
if item == '(':
balance += 1
else:
balance -= 1
if balance < 0:
return False
return balance == 0
result = []
generate([])
return result
def generateParenthesis(n):
def generate(lst):
# 生成的括号组合(lst)长度达到2*n时开始判断其是否有效
if len(lst) == 2 * n:
if valid(lst): # 使用valid判断括号组合是否有效
# 因为lst为列表,我们使用join()方法将lst变成字符串
# 并添加到结果列表result中
result.append("".join(lst))
else:
# 我们给空列表不断加入‘(’知道lst长度为2*n,进行有效判断
lst.append('(')
generate(lst)
# 执行if语句时最内层的递归函数释放,进行下一步pop()操作
# 为了获取全部的组合我们需要进行删除操作(pop)
# 并加入右括号
lst.pop()
lst.append(')')
generate(lst)
lst.pop()
def valid(lst):
balance = 0 # 标记值
for item in lst:
if item == '(':
balance += 1
else:
balance -= 1
# 在每一次balance的值改变后都判断balance的值
if balance < 0:
return False
return balance == 0
result = []
generate([]) # 给形参lst传入实参,即空列表
return result
join()函数使用
result = [] lst = ['(', ')', '(', '(', ')', ')'] result.append("".join(lst)) print(result)
输出:
['()(())']
较为难理解的还有递归过程
可以在balance = 0语句前加上print(lst),运行后即可看到递归过程是如何生成,和排列括号组合的。
解法一是先算出所有的括号组合在判断生成括号是否有效,那么我们可以在方法一递归的基础上使用回溯法来实现每一个生成的括号组合都是有效的。
为了保证生成的括号是有效的,我们需要添加一些限制条件。
当左括号的数量小于给定的数n时,我们添加左括号
当左括号的数量大于右括号时,我们添加右括号
增加了限制条件,我们也就不需要用balance来判断括号组合是否有效
def generateParenthesis(n):
result = []
def backtrack(lst, left, right):
print(lst)
if len(lst) == 2 * n:
result.append(''.join(lst))
return
if left < n:
lst.append('(')
backtrack(lst, left + 1, right)
lst.pop()
if right < left:
lst.append(')')
backtrack(lst, left, right + 1)
lst.pop()
backtrack([], 0, 0)
return result
def generateParenthesis(n):
result = []
def backtrack(lst, left, right):
print(lst)
if len(lst) == 2 * n:
result.append(''.join(lst))
return # 什么都不反回,仅作为递归的出口
# 两个限制条件(if语句)顺序可以替换
if left < n:
# 探索当前位置放入左括号的所有组合
lst.append('(')
# 核心回溯语句
backtrack(lst, left + 1, right)
# 将放入的左括号删除,因为该位置也可能可以放入右括号
# 我们删除后继续探索放入右括号的所有有效组合(下一个if语句)
lst.pop()
# 同理
if right < left:
# 探索当前位置放入右括号的所有组合
lst.append(')')
# 核心回溯语句
backtrack(lst, left, right + 1)
# 将放入的右括号删除,因为该位置也可能可以放入左括号
# 我们删除后继续探索剩下的有效组合
lst.pop()
backtrack([], 0, 0)
return result
今天就到这,明天见。
❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄end❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄