题目
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
一. 递归法
为了保证括号有效,添加过程中,左括号必须大于等于右括号,所以,递归过程中,如果左括号数等于右括号数,则直接添加左括号,如果左括号数大于右括号数,先复制一个相同的字符串,然后分别添加左括号和右括号。直到左括号数等于目标数,添加剩下的右括号。
js实现
/**
* @param {number} n
* @return {string[]}
*/
var generateParenthesis = function(n) {
function generate(str, left, right, n, answer) {
if (left === n) {
for (var i=0;i<n-right;i++) {
str += ')'
}
answer.push(str)
return answer
}
if (left === right) {
answer.concat(generate(str + '(', left+1, right, n, answer))
} else {
answer.concat(generate(str+'(', left+1, right, n, answer))
answer.concat(generate(str+')', left, right+1, n, answer))
}
return answer
}
return generate('', 0, 0, n, [])
}
复杂度分析
时间复杂度:O(4n/sqrt(n))
空间复杂度:O(4n/sqrt(n))
测试结果
✔ Accepted
✔ 8/8 cases passed (88 ms)
✔ Your runtime beats 40.86 % of javascript submissions
✔ Your memory usage beats 5.08 % of javascript submissions (40.9 MB)
二. 闭合数
(来自官方题解)对于每个闭合数 i
,我们知道起始和结束括号必定位于索引 0
和 2*i + 1
。然后两者间的 2*i
个元素一定是有效序列,其余元素一定是有效序列。
js实现
/**
* @param {number} n
* @return {string[]}
*/
var generateParenthesis = function(n) {
if (n === 0) {
return ['']
}
var answer = []
for (var i=0;i<n;i++) {
generateParenthesis(i).forEach(left => {
generateParenthesis(n-1-i).forEach(right => {
answer.push('(' + left + ')' + right)
})
})
}
return answer
}
复杂度分析
时间复杂度:O(4n/sqrt(n))
空间复杂度:O(4n/sqrt(n))
测试结果
✔ Accepted
✔ 8/8 cases passed (80 ms)
✔ Your runtime beats 62.34 % of javascript submissions
✔ Your memory usage beats 5.08 % of javascript submissions (38.2 MB)
三. 动态规划
当我们知道n-1
时的所有可能组合后,我们只需要考虑剩下的一组括号的位置,我们假设左括号始终添加在最左侧,那么右括号可以在剩下的位置之间插入即可,,那我们就可以对所有情况进行遍历:
“(” + 【i=p时所有括号的排列组合】 + “)” + 【i=q时所有括号的排列组合】
其中 p + q = n-1,且 p q 均为非负整数。
当p
从0
取到n-1
后,所有情况就遍历完了。
js实现
/**
* @param {number} n
* @return {string[]}
*/
var generateParenthesis = function(n) {
if (n === 0) {
return ['']
}
var answer = [[''], ['()']]
for (var i=2;i<n+1;i++) {
var left = []
for (var j=0;j<i;j++) {
answer[j].forEach(p => {
answer[i-1-j].forEach(q => {
left.push('(' + p + ')' + q)
})
})
}
answer.push(left)
}
return answer[n]
}
测试结果
✔ Accepted
✔ 8/8 cases passed (72 ms)
✔ Your runtime beats 81.73 % of javascript submissions
✔ Your memory usage beats 95.43 % of javascript submissions (34.3 MB)