22. 括号生成【中等】
leetcode:https://leetcode-cn.com/problems/generate-parentheses/
方法一:
动态规划
n:代表有n对括号
ans[i]:代表一共 i 对括号形成的所有组合
我们要求的是ans[n]
我们知道对于第n对括号是由一个左括号和一个右括号组成,而且无论多少对括号组成的排列的最左边一定是左括号
然后对于n对括号形成的组合中,剩下n-1对括号要么是在第n对括号中间,要么在第n对括号右边
所以假设我们知道1到 n - 1 括号形成的所有组合ans[1]到ans[n - 1],则对于n对括号组成的所有组合,无非就是
( + ans[q] + ) + ans[r]
我们知道ans[1] = ['()']
所以ans[2]的所有组合就是
( + ans[0] + ) + ans[1]
( + ans[1] + ) + ans[0]
这样就可以得到ans[1]和ans[2],利用之前计算的结果,然后依次递推可以计算出ans[3]、ans[4]。。。ans[n]
/** * @param {number} n * @return {string[]} */ var generateParenthesis = function(n) { // 第1组组合只有一种 let ans = [[],['()']]; // 还需要在原来基础上还需要增加i组括号 for (let i = 2; i <= n; i++) { ans[i] = []; let temp = []; // 遍历组合ans[j]和 ans[i - j]形成的所有组合 for (let j = 0; j < i; j++) { const qArr = ans[j]; const rArr = ans[i - j - 1]; // 右边没有 if (qArr.length === 0) { for (let r = 0, rLen = rArr.length; r < rLen; r++) { temp.push('()' + rArr[r]); } continue; } // 中间没有 if (rArr.length === 0) { for (let q = 0,qLen = qArr.length; q < qLen; q++) { temp.push('(' + qArr[q] + ')') } continue; } // 中间和右边都有 for (let q = 0,qLen = qArr.length; q < qLen; q++) { for (let r = 0, rLen = rArr.length; r < rLen; r++) { temp.push('(' + qArr[q] + ')' + rArr[r]); } } } ans[i] = temp; console.log(`ans[${i}]`, ans[i]) } return ans[n]; };
方法二:
深搜dfs + 剪枝
其实就是插入n次括号,每次有两种选择,左括号或者右括号,可以当做一个二叉树
边界:左右括都已经插入n个了,即形成要求的一组组合
不符合条件的:插入左括号或者右括号超过n个,或者右括号数量超过左括号,对于二叉树遍历过程中遇到这样的不再继续遍历,也就是【剪枝】
/** * @param {number} n * @return {string[]} */ var generateParenthesis = function(n) { let arr = []; // 二叉树深搜 const dfs = function (arr, str, l, r, n) { // 不符合组合条件的不再递归【剪枝】 if (l > n || r > n || r > l) return; if (l === n && r === n) { arr.push(str); return; } // 加左括号 dfs(arr, str + '(', l + 1, r, n); // 加右括号 dfs(arr, str + ')', l, r + 1, n); } dfs(arr, '', 0, 0, n); return arr; };
-----smile