一、题目内容 中等

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例1:

输入:n = 3 输出:["((()))","(()())","(())()","()(())","()()()"]

示例2:

输入:n = 1 输出:["()"]

提示:

  • 1 <= n <= 8

    二、解题思路

    看到这个题,我就在想回溯,但是又很难想出具体步骤,我们来缕一缕。
    为什么要用回溯,三个括号,我先放左括号,那接下来放做还是右呢?我先放左嘛,放完 3 个左,就肯定要是((()))。好了,回退一个左括号,合上右括号,再放左括号,就是这样(())()
    所以这就是为啥想用回溯。

那么怎么回溯呢,for 循环,好像用不着啊?那我回溯递归的时候,放几个左括号呢,n 个。那是不是就可以这样

  1. const path = []
  2. // left 代表,已经放入几个左括号
  3. const backTracking = (left, right) => {
  4. if (left < n) {
  5. path.push('(')
  6. backTracking(left + 1, right)
  7. path.pop()
  8. }
  9. }

那右括号呢?当我 path 有三个左括号(((,我就应该放三个右括号)))
当我 path 有两个左括号((,我就应该放两个右括号))。接着再放入一个左括号时(())(,我得再加一个)

下面代码中,让 right < left,也保证了,括号生成后,肯定是合法的。不会出现类似()))的情况

  1. const path = []
  2. // left 代表,已经放入几个左括号
  3. // right 代表,已经放入几个右括号
  4. const backTracking = (left, right) => {
  5. if (left < n) {
  6. path.push('(')
  7. backTracking(left + 1, right)
  8. path.pop()
  9. }
  10. if (right < left) {
  11. path.push(')')
  12. backTracking(left, right + 1)
  13. path.pop()
  14. }
  15. }

什么时候结束递归呢?肯定是指定了几个括号,path 满足条件之后就可以了

  1. const path = []
  2. const result = []
  3. // right 代表,已经放入几个右括号
  4. // left 代表,已经放入几个左括号
  5. const backTracking = (left, right) => {
  6. // 结束递归
  7. if (path.length === n * 2) {
  8. result.push(path.join(''))
  9. return
  10. }
  11. // ...
  12. }

三、具体代码

  1. /**
  2. * @param {number} n
  3. * @return {string[]}
  4. */
  5. var generateParenthesis = function (n) {
  6. const result = []
  7. const path = []
  8. const backTracking = (left, right) => {
  9. if (path.length === n * 2) {
  10. result.push(path.join(''))
  11. return
  12. }
  13. if (left < n) {
  14. path.push('(')
  15. backTracking(left + 1, right)
  16. path.pop()
  17. }
  18. if (right < left) {
  19. path.push(')')
  20. backTracking(left, right + 1)
  21. path.pop()
  22. }
  23. }
  24. backTracking(0, 0)
  25. return result
  26. };

四、其他解法