题目:
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,
给出 n = 3,生成结果为:["((()))","(()())", “(())()”, “()(())”, “()()()”]
思路:
方法一:暴力法
思路:
因为最后的结果必然是2n长度的字符串!!!
我们可以生成所有 2^{2n}个 ‘(’ 和 ‘)’ 字符构成的序列。然后,我们将检查每一个是否有效。
算法:
为了生成所有序列,我们使用递归。长度为 n 的序列就是 ‘(’ 加上所有长度为 n-1 的序列,以及 ‘)’ 加上所有长度为 n-1 的序列。
为了检查序列是否为有效的,我们会跟踪 平衡,也就是左括号的数量减去右括号的数量的净值。如果这个值始终小于零或者不以零结束,该序列就是无效的,否则它是有效的。
方法二:回溯法
思路和算法:
每次判断左括号数<n,右括号数<左括号数!!!
只有在我们知道序列仍然保持有效时才添加 ‘(’ or ‘)’,而不是像 方法一 那样每次添加。我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,
如果我们还剩一个位置,我们可以开始放一个左括号。 如果它不超过左括号的数量,我们可以放一个右括号。
方法三:闭合数
˼·
为了枚举某些内容,我们通常希望将其表示为更容易计算的不相交子集的总和。
考虑有效括号序列 S 的 闭包数:至少存在 index >= 0,使得 S[0], S[1], …, S[2index+1]是有效的。 显然,每个括号序列都有一个唯一的闭包号。 我们可以尝试单独列举它们。
算法
对于每个闭合数 c,我们知道起始和结束括号必定位于索引 0 和 2c + 1。然后两者间的 2*c 个元素一定是有效序列,其余元素一定是有效序列。
代码:(方法二)
void match_huishu(int N, vector<string>&ret, string temp, int left, int right) { if(temp.length() == 2*N) { ret.push_back(temp); } if(left < N) { match_huishu(N, ret, temp+'(', left+1, right); } if(right < left) { match_huishu(N, ret, temp+')', left, right+1); } }
文章来源: https://blog.csdn.net/qq_31820761/article/details/90697491