101 lines
2.7 KiB
JavaScript
101 lines
2.7 KiB
JavaScript
/**
|
||
* @param {number} n
|
||
* @return {string[]}
|
||
*/
|
||
const generateParenthesis = function (n) {
|
||
|
||
};
|
||
|
||
/*
|
||
这个题目也是一个典型的回溯算法题,一个一个的尝试就行了,问题在于如何检测有效括号,这里可以定义一个栈,这里可以参考
|
||
leetcode20题。
|
||
思路:每一次backtrack从头到尾尝试所有括号,尝试所有的排列可能,如果长度达到2*n检测是否符合要求,如果符合要求,
|
||
就收集结果,最后返回结果集
|
||
*/
|
||
function f1(n) {
|
||
const result = []; // 结果集
|
||
// 初始化括号数组
|
||
const brackets = [];
|
||
for (let i = 0; i < n; i++) {
|
||
brackets.push('(');
|
||
brackets.push(')');
|
||
}
|
||
const bLen = backtrack.length;
|
||
// 定义used数组,防止重复使用
|
||
const used = Array(bLen).fill(false);
|
||
const backtrack = (path) => {
|
||
// 如果path的长度等于brackets.length,并且有效括号数位n,则收集结果
|
||
if (path.length === bLen && checkBrackets(path)) {
|
||
result.push(path.join(''));
|
||
return;
|
||
}
|
||
for (let i = 0; i < bLen; i++) {
|
||
if (used[i]) continue;
|
||
path.push(brackets[i]);
|
||
used[i] = true;
|
||
backtrack(i + 1, path);
|
||
path.pop();
|
||
used[i] = false;
|
||
}
|
||
};
|
||
|
||
backtrack([]);
|
||
return Array.from(new Set(result));
|
||
}
|
||
|
||
/*
|
||
检测字符串中的括号是否符合要求
|
||
*/
|
||
function checkBrackets(backets) {
|
||
let count = 0;
|
||
|
||
for (const char of backets) {
|
||
if (char === '(') {
|
||
count++;
|
||
} else if (char === ')') {
|
||
count--;
|
||
}
|
||
|
||
// 如果右括号多于左括号,提前返回 false
|
||
if (count < 0) return false;
|
||
}
|
||
|
||
// 所有括号遍历完后,必须完全闭合
|
||
return count === 0;
|
||
}
|
||
|
||
/*
|
||
上面的思路会超时,通过全排列去找符合要求的再检测,会指数爆炸,当n>=5时就已经跑不动了,正确的做法应该是
|
||
递归的构造符合要求的字符串,当构造的字符串符合要求时,再收集结果。
|
||
*/
|
||
function f2(n) {
|
||
const result = []; // 结果集
|
||
|
||
/**
|
||
*
|
||
* @param {String} path 收集的括号组合
|
||
* @param {Number} left 左括号的数量
|
||
* @param {Number} right 右括号的数量
|
||
*/
|
||
const backtrack = (path, left, right) => {
|
||
// 如果长度达到2*n就收集结果
|
||
if (path.length === 2 * n) {
|
||
result.push(path);
|
||
return;
|
||
}
|
||
|
||
// 如果左括号未达到n就继续构造左括号
|
||
if (left < n) {
|
||
backtrack(`${path}(`, left + 1, right);
|
||
}
|
||
|
||
// 如果right >= left 再添加右括号会导致,缺少一个左括号和它闭合,所以只有当 right < left 时才添加右括号
|
||
if (right < left) {
|
||
backtrack(`${path})`, left, right + 1);
|
||
}
|
||
};
|
||
|
||
backtrack('', 0, 0);
|
||
return result;
|
||
}
|