[LeetCode22-中等-DFS] 括号生成

这道题考使用回溯(递归的一种)进行深度优先算法,题目是这样的

数字n代表生产括号的对数,写一个算法,返回所有有效的括号组合

比如  n =1 代表生成1对括号,显然答案就是 “()"

n = 2, 代表生成2对括号,  答案就是"()()","(())"

n=3 代表生成3对括号,答案就是 "((()))","()()()","(()())","()(())","(())()"  => 通过答案能发现什么规律么?

通过答案我们可以发现,我们把左括号'('看成一个字符,右括号')'也看成一个字符, 那么每个答案就是由2n个字符组成,每个字符是'('或者')'

=> 标准1. 答案是由一个字符串数组组成,字符串数组中的每一个字符串都是由2n个字符组成,其中每个字符都是'('或者')'

      标准2. 对于这个字符串数组中的每一个字符串, 从左往右遍历这个字符串,在任何时候,'('的个数都应该大于或者等于')'的个数,否则就是无效的

      标准3. 对于这个字符串数组中的每一个字符串,从左往右遍历这个字符串,当遍历完成时,'('的个数一定会等于')"的个数

我们可以这样来理解,就是现在我手上有n个'(', 还有n个')', 我现在要一个一个字符【字符是'('或者')'两种之一】往一个string字符串里面放,把n个'(’和 n个')'都放进去, 所以最后这个string长度一定是2n =>这里会各种各样的放入方法,所有放入方法最后组成一个结果集 List<string>

然后,在这些结果集List<string>中,找出有效的结果 =》 也就是满足上面3条的结果

 

 

现在我们把它这么来看: 

手中的字符数 => n 个 '(' 和 n 个')'

结果字符串string中的字符数 => 0 个     =>  我们的目标是把手中的字符一个一个的放入到结果字符串string中,但是要满足上面的3条标准。按照上面的第2条标准,你在放入的过程中,任何时候 结果字符串string中的左括号'('个数都应该大于或者等于右括号')'个数 =》 这句话等价于  任何时候手中的字符数中的左括号'('个数都应该都应该小于等于右括号')'的个数

写代码之前,我们来写逻辑

假设 结果字符串列表为List<string> res;   任意一个结果字符串为str, 任何时候我们手中左括号'('个数为left => left初始值为n, 我们手中右括号')'个数为right => right初始值为n

 

 

 

1.  如果我们手中的左括号个数left 和右括号个数right都变成了0, 那么说明已经生成了一个完整的结果字符串str, 把它加入到结果列表res中

            left == 0 && right ==0,  res.Add(str);

2.  如果我们手中左括号个数 小于或者等于 右括号个数 (上面分析过,不应该大于,大于的情况不是有效的结果), 那么进行如下处理

      left <= right  

      if left == right  表明此时现在放入到结果字符串str中的左括号也和右括号相等, 这个时候,我们只能再往str里面放入左括号 (满足上面的标准2)

      比如 n =2, str = "()", 此时手中还有1个'(", 还有1个')', 也就是 left =1, right = 1, 此时你只能往str中再放入一个'(' 

      if left < right  手中剩下的左括号小于右括号,表明此时放入结果字符串str中的左括号大于右括号, 此时为了满足标准2,我们可以往str中放入左括号,也可以放入右括号,都会继续满足标准2

 现在我们来尝试写代码


 1 public class Solution
 2     {
 3         List<string> res = new List<string>(); //存放最终的结果字符串列表,其中的每个元素都是一个有效的结果
 4 
 5         public List<string> GenerateParenthesis(int n)
 6         {
 7             if (n > 0)
 8             {
 9                 //调用递归方法,初始化结果字符串为空字符串,手中剩下的左括号数为n,手中剩下的右括号数为n 
10                 getParenthesisStr("", n, n);
11             }
12             return res;
13         }
14 
15         /// <summary>
16         ///  这个是产生有效结果字符串的递归方法
17         /// </summary>
18         /// <param name="str">结果字符串,长度为2n,其中每个字符为'('或者')'</param>
19         /// <param name="left">手中还剩下的左括号'('的个数,初始值为n</param>
20         /// <param name="right">手中还剩下的右括号')'的个数,初始值为n</param>
21         private void getParenthesisStr(string str, int left, int right)
22 
23         {
24             if (left == 0 && right == 0) //表明手中左括号右括号都没有了,全部放入到了结果字符串中
25             {
26                 res.Add(str);
27             }
28 
29             if (left <= right) //按照上面分析,手中的左括号必须小于等于手中的右括号, 才会产生有效结果
30             {
31 
32                 if (left == right) //此时,手中的左括号等于手中的右括号,只能往结果字符串中加入左括号,才能满足标准2
33                 {
34 
35                      //要把手中的左括号放一个到结果字符串中,前提是此时手中还有左括号,也就是left>0, 但其实这个条件多余,因为如果此时left = 0,那么按照它外层的条件left == right, 那就是left == right == 0, 代码就会进前面的条件,不会来到这里 
36                     if (left > 0)
37                     {
38                         getParenthesisStr(str + "(", left - 1, right);
39                     }
40                 }
41                 
42    //否则,就是手中的左括号小于手中的右括号 left < right,此时我们可以往结果字符串str中加入左括号,或者加入右括号,都满足标准2
43                 else
44                 {
45                     //要把手中的左括号放一个到结果字符串中,前提是此时手中还有左括号,也就是left>0
46                     if (left > 0)
47                     {
48                         getParenthesisStr(str + "(", left - 1, right);
49                     }
50 
51                     //要把手中的右括号放一个到结果字符串中,前提是此时手中还有右括号,也就是right>0,但这里这个条件多余,因为此时前提是left < right, 如果riht =0, 那left岂不是负数了,显然不可能
52                     if (right > 0)
53                     {
54                         getParenthesisStr(str + ")", left, right - 1);
55                     }
56                 }
57             }
58         }
59     }

我们再把上面代码中多余的判断条件去掉,代码更改如下

 

 1 public class Solution
 2     {
 3         List<string> res = new List<string>(); //存放最终的结果字符串列表,其中的每个元素都是一个有效的结果
 4 
 5         public List<string> GenerateParenthesis(int n)
 6         {
 7             if (n > 0)
 8             {
 9                 //调用递归方法,初始化结果字符串为空字符串,手中剩下的左括号数为n,手中剩下的右括号数为n 
10                 getParenthesisStr("", n, n);
11             }
12             return res;
13         }
14 
15         /// <summary>
16         ///  这个是产生有效结果字符串的递归方法
17         /// </summary>
18         /// <param name="str">结果字符串,长度为2n,其中每个字符为'('或者')'</param>
19         /// <param name="left">手中还剩下的左括号'('的个数,初始值为n</param>
20         /// <param name="right">手中还剩下的右括号')'的个数,初始值为n</param>
21         private void getParenthesisStr(string str, int left, int right)
22 
23         {
24             if (left == 0 && right == 0) //表明手中左括号右括号都没有了,全部放入到了结果字符串中
25             {
26                 res.Add(str);
27             }
28 
29             if (left <= right) //按照上面分析,手中的左括号必须小于等于手中的右括号, 才会产生有效结果
30             {
31 
32                 if (left == right) //此时,手中的左括号等于手中的右括号,只能往结果字符串中加入左括号,才能满足标准2
33                 {
34                         getParenthesisStr(str + "(", left - 1, right);                
35                 }
36                 
37    //否则,就是手中的左括号小于手中的右括号 left < right,此时我们可以往结果字符串str中加入左括号,或者加入右括号,都满足标准2
38                 else
39                 {
40                     //要把手中的左括号放一个到结果字符串中,前提是此时手中还有左括号,也就是left>0
41                     if (left > 0)
42                     {
43                         getParenthesisStr(str + "(", left - 1, right);
44                     }
45                     getParenthesisStr(str + ")", left, right - 1);                    
46                 }
47             }
48         }
49     }

 

posted on 2023-12-20 13:55  新西兰程序员  阅读(5)  评论(0编辑  收藏  举报