「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。
题目:设计函数输出所有可能且符合括号规则的n对括号排列。
解题思路
因为之前做过一个判断括号是否有效的题目,因此本题的第一反应就是暴力获得所有可能的括号对,之后再遍历判断每个括号的有效性,时间效率不用想就非常低(首先要获得所有可能的括号对,之后进行括号对合法性的判断),方法的话也很简单,通过递归即可,代码可以参考下面的:
public static void getAll(String s, int left, int right, ArrayList result){
if(left==0&&right==0){
result.add(s);
return;
}
if(left>0) {
getAll(s + "(", left - 1, right, result);
}
if(right>0) {
getAll(s + ")", left, right - 1, result);
}
}
之后循环遍历list,调用之前判断括号是否合法函数即可。注意上述递归过程,实际上就是遍历一颗完全二叉树,但在遍历二叉树的时候,根据已知条件进行了剪枝,如上述代码的判断左右剩余括号大于0的条件,那有没有一种办法可以对二叉树进一步的剪枝,直接获得我们的正确结果,答案是有的。实际上本题隐藏了一个条件,当左括号剩余数量大于等于右括号的时候,字符串只能加左括号,若左括号小于右括号,那么加左右括号都行(其中左括号需要判断是否大于0,而右括号不需要,这是因为这是在左括号小于右括号的前提下执行的),递归结束得到的就是最终结果,代码如下:
public static List<String> generateParenthesis(int n) {
ArrayList<String> strings = new ArrayList<>();
getP("", n, n, strings);
return strings;
}
private static void getP(String s, int left, int right, ArrayList result){
if(left==0&&right==0){
result.add(s);
return;
}
if(left<right){
if(left>0){
getP(s+"(", left-1, right, result);
}
getP(s+")", left, right-1, result); // 函数调用的过程!!!s不变
}else {
getP(s+"(", left-1, right, result);
}
}
我看题解里面有人问当n等于3的时候,()()()这个情况是怎么产生的,如果可以理解((()))的产生过程,而不理解()()()的话,可能对递归的调用过程不是很理解,上述代码我加了一个注释,其注释那一行执行的是函数调用的过程,这个过程注意s是不变的,可能是误解根据函数调用过程首先判断左括号剩余数大于0就调用(没错),但之后会再次调用s + ")"这个过程,此时的s不变!
时间复杂度和空间复杂度感觉不太好分析。。。