括号生成

方法一:暴力破解

生成所有可能的字符串组合,然后检查有效的字符串。一共可以生成的字符串个数为:2^{2n}

为了生成所有序列,我们使用递归。长度为 n 的序列就是 '(' 加上所有长度为 n-1 的序列,以及 ')' 加上所有长度为 n-1 的序列。

为了检查序列是否为有效的,我们会跟踪平衡,也就是左括号的数量减去右括号的数量的净值。如果这个值始终小于零或者不以零结束,该序列就是无效的,否则它是有效的。

package leetcode.problem22;


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

class Solution2 {
    
    public static List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<>();
        getAll(new char[2 * n], 0, result);
        return result;
    }

    private static void getAll(char[] chars, int i, List<String> result) {
        if (i == chars.length){
            if (valid(chars)){
                result.add(new String(chars));
            }
            return;
        }else {
            chars[i] = '(';
            getAll(chars, i + 1, result);
            chars[i] = ')';
            getAll(chars, i + 1, result);
        }
    }

    private static boolean valid(char[] chars) {
        int t = 0;
        for (char c : chars){
            if (c == '('){
                t++;
            }else if (c == ')'){
                t--;
            }
            if (t < 0){
                return false;
            }
        }
        return t == 0;
    }

}

复杂度分析:

时间复杂度:O(2^{2n}n),对于每一个子序列验证其合法性的时间复杂度为O(n)

空间复杂度:O(2^{2n}n)

方法二:回溯法

先写n个左括号,然后就写右括号,每当完成一组之后,就吧字符串存起来。然后再倒退步骤到写第n-1个左括号,然后写右括号,在写左括号,再全写右括号。依次回溯递归,每完成一趟就回到能再改变的位置。

package leetcode.problem22;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class Solution3 {
    public List<String> generateParenthesis(int n) {
        List<String> result = new ArrayList<>();
        solve(result,"",0,0,n);
        return result;
    }

    private void solve(List<String> result, String s, int start, int end, int n) {
        if (s.length() == 2 * n){
            result.add(s);
            return;
        }
        if (start < n){
            solve(result, s + "(",start + 1,end,n);
        }
        if (end < start){
            solve(result, s + ")",start,end + 1,n);
        }
    }
}

方法三

先是找左括号,每找到一个左括号,就在其后面加一个完整的括号,最后再在开头加一个(),就形成了所有的情况,需要注意的是,有时候会出现重复的情况,所以用set数据结构,好处是如果遇到重复项,不会加入到结果中,最后再把set转为list即可。

n=1:    ()

n=2:    (())    ()()

n=3:    (()())    ((()))    ()(())    (())()    ()()()   
package leetcode.problem22;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

class Solution {
    public List<String> generateParenthesis(int n) {
        Set<String> result = new HashSet<>();
        if (n == 0){
            result.add("");
        }else {
            List<String> pre = generateParenthesis(n - 1);
            for (String string : pre){
                for (int i = 0; i < string.length(); i++) {
                    if (string.charAt(i) == '('){
                        result.add(string.substring(0, i + 1) + "()" + string.substring(i + 1 ));
                    }
                }
                result.add("()" + string);
            }
        }
        return new ArrayList<>(result);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值