力扣22.括号生成
力扣刷题 8

原题,题目描述:

61a37b05-9748-483b-98cf-344dad75da4b.png

分类标签也是回溯,其实我做了这么多天的回溯题后,我发现回溯其实和动态规划其实也蛮像的(其实不如说递归和动态规划的思想本来就挺像,至少我是这么认为的)。这道题题目很简单,就是给定一个数字,我们需要使用这个长度来生成一个括号序列,并且必须是符合条件的括号序列,具体看原题的描述。

看到这题的时候还是思考了一下的。然后我产生的第一思路如下:

思路一

我们需要有效的括号序列,那我们可以以一个完整的括号为单位,在序列里面移动,如下:

例如已经回溯到了当前函数,传回来的括号序列是 () ,我们可以以 () 为单位移动:(()) ()() 

代码一

这样有一个坏处,那就是会产生一些重复的序列,不过我们使用set去重即可,我们这里直接给出代码:

class Solution {
    public List<String> generateParenthesis(int n) {
        if (n == 1) {
            ArrayList<String> res = new ArrayList<>();
            res.add("()");
            return res;
        }
        List<String> list = generateParenthesis(n - 1);

        HashSet<String> set = new HashSet<>();

        for (String s : list) {
            int length = s.length();
            StringBuilder sb = new StringBuilder(s);
            for (int i = 0; i < length; i++) {
                char c = s.charAt(i);
                if (c=='('||c==')'){
                    sb.insert(i+1,"()");
                    set.add(sb.toString());
                    sb.delete(i+1,i+3);
                }
            }
        }
        return set.stream().toList();
    }
}

提交后跑了5毫秒,只打败了百分之10左右。这个成绩当然是不满意的,于是我就在寻找优化点,我尝试了很多优化,但是都不太能改善这个成绩。于是我去看了官解,官解给出了三种解答,一种是暴力,这里我们不管,一种是我上述的解法一,我们学习最后的一种。

思路二

括号都是成对存在,我们给出括号多少n,就可以确认左右括号的数量,那我们只要在满足这个数量的前提下,再满足有效即可。那我们可以去一个个放置左右括号。首先左括号的放置是无要求的,只要不超过n即可,右括号有要求,思考一下:首先一个左括号都没放的时候,当然是不能放置右括号的。然后就是当前序列里,右括号的数量一定得小于左括号数量(在当前右括号放下前),为什么,思考一下,如果右括号数量超过的左括号,那左边就是没有闭合的,这个原理比较显然。我们将括号放置完毕后,也就是左右括号的剩余数量都等于0的时候,直接将序列添加进集合即可。

代码二

我们看代码:

class Solution {
    private ArrayList<String> generateParenthesisRes = new ArrayList<>();

    public List<String> generateParenthesis(int n) {
        generateParenthesis2(n, n, new StringBuilder());
        return generateParenthesisRes;
    }

    public void generateParenthesis2(int left, int right, StringBuilder sb) {
        if (left == 0 && right == 0) {
            generateParenthesisRes.add(sb.toString());
        }

        if (left > 0) {
            sb.append('(');
            generateParenthesis2(left - 1, right, sb);
            sb.deleteCharAt(sb.length() - 1);
        }

        if (left < right) {
            sb.append(')');
            generateParenthesis2(left, right-1, sb);
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

这份代码的速度和空间都很优秀。提交后接近双百。这道题的时空复杂度计算比较复杂,所以这里不做分析,想了解可以去看官方的分析。

力扣22.括号生成
https://www.than.pw/archives/019c74ef-f0f3-7029-8a59-f1b83d3cf7f2
作者
than
发布于
更新于
许可