22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
暴力解法(回溯+dfs)
每个位置有两种可能左括号或者右括号,需要额外判断括号的有效性
时间复杂度: O(2^2n * n)
空间复杂度: O(n)
可以优化不需要判断有效性。
var generateParenthesis = function(n) {
let path = [], result = [], arr = ['(', ')'];
let isvalidlog = function (str) {
let stack = [], head, l = '(', r = ')';
for(let i of str) {
if (stack.length === 0 && r === i) return false;
l === i ? (stack.push(i), head = l) : (stack.pop(), head = stack[stack.length - 1]);
}
return stack.length ? false : true;
}
let makelog = function (arr) {
if (path.length === 2*n) {
let str = path.join('');
// console.log(str, isvalidlog(str))
isvalidlog(str) ? result.push(str) : null;
return;
}
for(let i of arr) {
path.push(i);
makelog(arr);
path.pop();
}
}
makelog(arr);
return result;
};
优化暴力解法(回溯+dfs)
括号成对,右括号个数不能超过左括号
var generateParenthesis = function(n) {
let result = [];
let makelog = function (path, left, right) {
if (left > n || right > left) return;
if (path.length === 2*n) {
result.push(path);
return;
}
makelog(path + '(', left+1, right);
makelog(path + ')', left, right+1);
}
makelog('', 0, 0);
return result;
};
自底向上的解法(动态规划)
这个问题不满足动态规划的“重复子问题”要求,所以不是动态规划。这个解法只是一个普通的自底向上的解法,严格意义上来说不属于动态规划。
关于动态规划的推荐文章动态规划
这里引用一个博主的思路:
作者:yuyu-13
链接:https://leetcode.cn/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/
来源:力扣(LeetCode)
本题最核心的思想是,考虑 i=n 时相比 n-1 组括号增加的那一组括号的位置。
当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 “( )”,我们认为这一组是相比 n-1 增加进来的括号。
那么,剩下 n-1 组括号,要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。
既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历:
“(” + 【i=p时所有括号的排列组合】 + “)” + 【i=q时所有括号的排列组合】
其中 p + q = n-1,且 p q 均为非负整数。
事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。
注:上述遍历是没有重复情况出现的,即当 (p1,q1)≠(p2,q2) 时,按上述方式取的括号组合一定不同。
前提是单独拿出来的括号E的左边在N个括号所有排列组合情况中都是处于最左边,所以不存在括号位于括号E的左边的情况, 这个算法主要的基点就是将排列组合的情况分为了括号内和括号外这两种情况,且仅存在两种情况.
简单来说,在求N个括号的排列组合时,把第N种情况(也就是N个括号排列组合)视为单独拿一个括号E出来,剩下的N-1个括号分为两部分,P个括号和Q个括号,P+Q=N-1,然后这两部分分别处于括号E内和括号E的右边,各自进行括号的排列组合。由于我们是一步步计算得到N个括号的情况的,所以小于等于N-1个括号的排列组合方式我们是已知的,且P+Q=N-1,P和Q是小于等于N-1的,所以我们能直接得到P个和Q个括号的情况,进而得到N个括号的结果!
var generateParenthesis = function(n) {
let dp = [];
dp[0] = [''];
dp[1] = ['()'];
for(let i = 2; i <= n; i++) {
dp[i] = [];
for(let p = i-1,q = 0; p > -1; p--, q++) {
let qlen = dp[q].length;
while(qlen > 0) {
qlen--;
let plen = dp[p].length;
while(plen > 0) {
plen--;
dp[i].push(`(${dp[q][qlen]})${dp[p][plen]}`);
}
}
}
}
console.log(dp)
return dp[n];
};