Leetcode22——括号生成(回溯法)

  • Post author:
  • Post category:其他





1. 写在前面


回溯[sù]

:意思是逆着水流的方向走、逆水而行,逆流而上


1


。我一直读成[shuò]。


框[kuàng]架

1.建筑工程中,由梁、柱等联结而成的结构:完成主体~工程。

2.比喻事物的基本组织、结构:这部长篇小说已经有了一个大致的~。

得,语文没学好。



2. 回溯法基本思想

在许多递归问题当中,我们采取的方法都是穷尽所有的可能,从而找出合法的解。但是在某些情况下,当递归到某一层的时候,根据设置的判断条件,可以 judge 此解是不合法的。在这种情况下,我们就没必要再进行深层次的递归,从而可以提高算法效率。这一类算法我们称为“回溯法”,设置的判断条件称为“剪枝函数”。


2



个人觉得啊,回溯法可以类比为一棵自上而下的树,每一次

满足题目要求

的选择就是一个节点。当

满足题目结束条件

时,根到当前叶子节点的路径就是一个可行解。



3. 回溯法基本框架

回溯法框架


3

1、路径:也就是已经做出的选择。
2、选择列表:也就是你当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。
代码方面,回溯算法的框架:
result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return

for 选择 in 选择列表:
    做选择
    backtrack(路径, 选择列表)
    撤销选择

其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。



4. 题目描述

  1. 括号生成

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

    示例:

    输入:n = 3

    输出:[

    “((()))”,

    “(()())”,

    “(())()”,

    “()(())”,

    “()()()”

    ]



5. 代码

参考回溯法框架三点的解题。

  • 1.路径:也就是已经做出的选择。 ->这里使用StringBuilder保存已走路径,方便到时候回溯 — stringBuilder.deleteCharAt(X);
  • 2.选择列表:也就是你当前可以做的选择。 ->每次都可以选择 左括号 或者 右括号,但有限制条件:

    1.左右括号数量均不能超过n。2.当前StringBuilder的右括号数量必须小于左括号数量

  • 3.结束条件:也就是到达决策树底层,无法再做选择的条件。->StringBuilder长度为2*n。
	List<String> result = new ArrayList<String>();

    public List<String> generateParenthesis(int n) {
        //1、路径:也就是已经做出的选择。
        StringBuilder stringBuilder = new StringBuilder();

        //本题有两个需要注意:
        // 1.左括号和右括号数目均不能超过n
        // 2.如何判断括号合法?————————————————————当前已保存的括号数关系需满足:right括号数 <= left括号数。


        backTrack(n, 0, 0, stringBuilder);
        return result;
    }

 	/**
     * 回溯计算
     *
     * @param num           括号对数
     * @param leftNum       已有左括号数量
     * @param rightNum      已有右括号数量
     * @param stringBuilder 已保存的路径
     */
    private void backTrack(int num, int leftNum, int rightNum, StringBuilder stringBuilder) {

        //结束条件
        if (stringBuilder.length() >= num * 2) {
            result.add(stringBuilder.toString());
            return;
        }

        //做选择
        if (leftNum < num) {
            stringBuilder.append("(");
            backTrack(num, ++leftNum, rightNum, stringBuilder);
            //撤销选择
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            --leftNum;
        }

        //咱再做一次选择
        if (rightNum < leftNum) {
            stringBuilder.append(")");
            backTrack(num, leftNum, ++rightNum, stringBuilder);
            //撤销选择
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
            --rightNum;
        }
    }



6. 总结

一开始做题用的是暴力递归法,当括号总数达到2*n时才判断括号是否有效”((((((“,看了题解之后才知道回溯法。回溯法题目做的还是不多,得多刷几题找找感觉。加油!

 	/**
     * 判断括号是否有效
     * @param array char数组
     * @return 是否有效
     */
    private boolean parenthesIsValid(char[] array) {
        int balance = 0;

        for (char c : array) {
            if ('(' == c) {
                balance++;
            } else {
                balance--;
            }

            if (balance < 0) {
                return false;
            }
        }

        return balance == 0;

    }

完~



  1. 百度百科

    .

    ↩︎


  2. [算法笔记] 回溯法总结

    .

    ↩︎


  3. Leetcode刷题java之39. 组合总和(回溯法以及回溯法框架)

    .

    ↩︎



版权声明:本文为weixin_42683408原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。