LeetCode-22题:括号生成(原创)

【题目描述】

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 【题目链接】. - 力扣(LeetCode)

【解题代码】

java 复制代码
package dp;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class GenerateParenthesis {
    // 生成的有效括号字符串列表
    private List<String> result;
    // StringBuilder变量,用于生成有效括号字符串
    private StringBuilder sb;
    // 左括号数量
    private int count1;
    // 右括号数量
    private int count2;

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        List<String> result = new GenerateParenthesis().generateParenthesis(3);
        System.out.println("result = " + Arrays.toString(result.toArray()));
        System.out.println("函数执行时间:" + (System.currentTimeMillis() - start) + "MS");
    }

    public List<String> generateParenthesis(int n) {
        // 初始化各个变量
        result = new ArrayList<>();
        sb = new StringBuilder();
        count1 = 0;
        count2 = 0;
        // 有效的括号字符串肯定,第一个肯定是左括号
        generateParenthesis(n, 0);
        // 返回最终结果
        return result;
    }

    /**
     * 生成有效括号字符串
     *  @param n 有效括号组数量
     *  type:当前添加括号的类型,0:左括号,1:右括号
     **/

    private void generateParenthesis(int n, int type) {
        // 当前添加左括号
        if (type == 0) {
            sb.append('(');
            count1++;
        } else { // 当前添加右括号
            sb.append(')');
            count2++;
            // 右括号数量等于n,说明新的有效括号组完成,添加到结果类表中
            if (count2 == n) {
                result.add(sb.toString());
                return;
            }
        }
        // 先处理左括号,如果左括号数小于n,添加左括号
        if (count1 < n) {
            generateParenthesis(n, 0);
            // 回溯,删除这一层递归函数里添加的左括号,并将左括号数减一
            sb.deleteCharAt(sb.length() - 1);
            count1--;
        }
        // 再处理右括号,右括号只能数量小于左括号时才能添加
        if (count2 < count1) {
            generateParenthesis(n, 1);
            // 回溯,删除这一层递归函数里添加的左括号,并将左括号数减一
            sb.deleteCharAt(sb.length() - 1);
            count2--;
        }
    }

}

【解题思路】

分析题目,仔细思考得到以下几个思路点:

  1. 所谓有效括号就是最终的左括号数和右括号数一样;
  2. 右括号出现时,前面至少有一个左括号能与之匹配,也就是右括号的数量必须小于等于已有的左括号数。
  3. 此道题目可以按照**"回溯递归"**的方式进行处理 ,即当前一步添加左括号->然后递归处理下一步->递归回到这一层->然后弹出左括号->然后添加右括号的->然后递归处理下一步。
  4. 第一步肯定要添加左括号

【解题步骤】

  1. 首先要给解题类添加几个成员变量:包括最终的结果字符串列表、存储过程字符串的StringBuilder、左右括号的数量等,并在构造函数中进行初始化

    java 复制代码
    // 生成的有效括号字符串列表
    private List<String> result;
    // StringBuilder变量,用于生成有效括号字符串
    private StringBuilder sb;
    // 左括号数量
    private int count1;
    // 右括号数量
    private int count2;
    
    public GenerateParenthesis(){
        // 初始化各个变量
        result = new ArrayList<>();
        sb = new StringBuilder();
        count1 = 0;
        count2 = 0;
    }
  2. 定义一个**"回溯递归"生成有效括号字符串的函数generateParenthesis** ,传入参数包括有效括号组数量,当前添加括号类型

    java 复制代码
    /**
     * 生成有效括号字符串
     *  @param n 有效括号组数量
     *  type:当前添加括号的类型,0:左括号,1:右括号
     **/
    private void generateParenthesis(int n, int type)
  3. generateParenthesis 函数内部第一步:根据当前要添加括号类型,存储对应的括号字符串并进行计数处理。如果是右括号则判断当前括号组数是否等于n,如果等于则将当前字符串加入结果列表中

    java 复制代码
    // 当前添加左括号
    if (type == 0) {
        sb.append('(');
        count1++;
    } else { // 当前添加右括号
        sb.append(')');
        count2++;
        // 右括号数量等于n,说明新的有效括号组完成,添加到结果类表中
        if (count2 == n) {
            result.add(sb.toString());
            return;
        }
    }
  4. generateParenthesis 函数内部第二步:下一步递归添加左括号,递归完毕后进行回溯

    java 复制代码
    // 先处理左括号,如果左括号数小于n,添加左括号
    if (count1 < n) {
        generateParenthesis(n, 0);
        // 回溯,删除这一层递归函数里添加的左括号,并将左括号数减一
        sb.deleteCharAt(sb.length() - 1);
        count1--;
    }
  5. generateParenthesis 函数内部第二步:下一步递归添加右括号,递归完毕后进行回溯,只有在右括号数量小于左括号的情况下才能添加右括号

    java 复制代码
    // 再处理右括号,右括号只能数量小于左括号时才能添加
    if (count2 < count1) {
        generateParenthesis(n, 1);
        // 回溯,删除这一层递归函数里添加的左括号,并将左括号数减一    
        sb.deleteCharAt(sb.length() - 1);
        count2--;
    }
  6. 最后主函数generateParenthesis里调用递归函数,从第一个左括号添加开始,最后返回结果列表即可

    java 复制代码
    public List<String> generateParenthesis(int n) {
        // 有效的括号字符串肯定,第一个肯定是左括号
        generateParenthesis(n, 0);
        // 返回最终结果
        return result;
    }

【思考总结】

  1. 掌握"回溯":回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试;
  2. 大的算法框架定下来后, 要细心找出业务里面的逻辑关键点,这道理题的关键点就在于"只有在右括号数量小于左括号的情况下才能添加右括号"
  3. 算法优化里,要掌握所运用语言库的性能最优方式,比如这里字符串处理使用了Java库里面的StringBuilder
  4. LeetCode解题之前,一定不要看题解,看了就"破功"了!
相关推荐
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
Tisfy1 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分
Mephisto.java2 小时前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli2 小时前
滑动窗口->dd爱框框
算法
丶Darling.2 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5202 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
jiyisuifeng19912 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
꧁༺❀氯ྀൢ躅ྀൢ❀༻꧂3 小时前
实验4 循环结构
c语言·算法·基础题
新晓·故知3 小时前
<基于递归实现线索二叉树的构造及遍历算法探讨>
数据结构·经验分享·笔记·算法·链表
总裁余(余登武)3 小时前
算法竞赛(Python)-万变中的不变“随机算法”
开发语言·python·算法