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

示例 1:

  1. Input: n = 3
  2. Output: ["((()))","(()())","(())()","()(())","()()()"]

示例 2:

  1. Input: n = 1
  2. Output: ["()"]

提示:

  • 1 ≤ n ≤ 8

思路

本题可构建一棵求解树,如下图所示:
22-1.png

分析题目我们可以发现,在合法的括号中,第一个不能是右括号,或者说,当左括号的个数和右括号的个数相等时,我们不能选右括号。

DFS需要一个终止递归的条件,本题的终止条件是什么呢?因为括号是成对出现的,所以当path的长度等于2 * n时,我们就停止递归。例如n=3,那最终会生成长度为2 * 3 = 6的字符串。

我们分别为做左括号和右括号维护一个计数器。这个计数器的功能类似于bool[] visited数组。

代码

  1. class Solution {
  2. public:
  3. vector<string> generateParenthesis(int n) {
  4. vector<string> answer;
  5. if(n == 0) return answer;
  6. if(n == 1) {
  7. answer.emplace_back( "()" );
  8. return answer;
  9. }
  10. int* visited = new int[n];
  11. for(int i = 0; i < n; i++) visited[i] = n;
  12. string path;
  13. string token = "()";
  14. dfs(n, answer, token, visited, path);
  15. delete[] visited;
  16. return answer;
  17. }
  18. void dfs
  19. (
  20. const int n,
  21. vector<string>& answer,
  22. const string& token,
  23. int visited[],
  24. string& path
  25. ) {
  26. // 1. Exit condition
  27. if( path.size() == 2 * n ) {
  28. answer.emplace_back( path );
  29. return;
  30. }
  31. // 2. Walk every node that not visited
  32. if( visited[0] > 0 ) {
  33. string node = path + token[0];
  34. visited[0]--;
  35. dfs(n, answer, token, visited, node);
  36. visited[0]++;
  37. }
  38. if( visited[1] > 0 && visited[0] != visited[1] ) {
  39. string node = path + token[1];
  40. visited[1]--;
  41. dfs(n, answer, token, visited, node);
  42. visited[1]++;
  43. }
  44. }
  45. };