import java.util.*;
import java.util.stream.Collectors;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return string字符串ArrayList
     */
    public ArrayList<String> generateParenthesis (int n) {
        // write code here
        // 根据左括号数量到达了长度的时候 到达了退出条件 
        // 然后还有就是 连续一个左括号   连续两个左括号  连续 3 个左括号的场景
        // 可以使用回溯找到所有的左括号  然后使用括号的合法性来做校验 来过滤后得到所有的合法 值
        

        char[] num=new char[2*n];
        for(int i=0;i<n;i++){
            num[i]='(';
        }
        for(int i=n;i<2*n;i++){
            num[i]=')';
        }

        boolean[] used = new boolean[num.length];
        ArrayList<String> result = new ArrayList<>();
        LinkedList<Character> trace = new LinkedList<>();
        backtrack(result, used, trace, num);
        return result;
    }




    private void backtrack(ArrayList<String> result, boolean[] used, 
                           LinkedList<Character> trace, char[] num) {
        if (trace.size() == num.length) {
           String ss= trace.stream().map(String::valueOf).collect(Collectors.joining());
            result.add( ss);
            return;
        }
         
        if(trace.size()!=0 && trace.get(0)==')'){
          return;
        }
        for (int i = 0; i < num.length; i++) {
                
            // 剪枝条件:当前数字与前一个相同,且前一个未被使用 => 跳过
            if (used[i]) {
                continue;
            }
       
            // trace 如果左括号数量>右括号数量的时候 才可以使用右括号 

            if (i > 0 && num[i] == num[i - 1] && !used[i - 1]) {
                continue;
            }

            if(num[i]==')'){
                // 必须是左括号数量大于右括号数量 否则继续
                long leftcount=trace.stream().filter(item->String.valueOf(item).equals("(")).count();   
                long rightcount=trace.stream().filter(item->String.valueOf(item).equals(")")).count();             
                 if(leftcount<=rightcount){
                    return;
                }
            }

            used[i] = true;
            trace.add(num[i]);

            System.out.println(i);
            System.out.println(trace);
            backtrack(result, used, trace, num);
            trace.removeLast();
            used[i] = false;
        }
    }

}