Java 实现括号生成:回溯法详解
括号生成问题是一道经典的回溯算法题目。题目要求我们生成所有可能的有效括号组合,对于给定的 n
对括号,这是算法面试中的常见问题。本文将详细讲解如何使用 Java 实现该问题的解决方案。
问题描述
给定 n
对括号,编写一个函数来生成所有可能的并且有效的括号组合。
示例:
- 输入:
n = 3
- 输出:
["((()))", "(()())", "(())()", "()(())", "()()()"]
解决思路
解决这个问题的关键在于回溯算法(Backtracking)。回溯是一种试探法,主要用于解决那些需要找出所有可能解的问题。通过回溯,我们可以生成所有可能的括号组合,并在生成过程中只保留有效的组合。
核心思路:
-
定义递归函数:
- 我们定义一个递归函数
backtrack(current, open, close, max)
,其中:current
:当前生成的括号组合字符串。open
:已使用的左括号数。close
:已使用的右括号数。max
:总括号对数n
。
- 我们定义一个递归函数
-
递归终止条件:
- 如果
current
的长度等于2*max
(即n
对括号已用完),则生成了一个完整的括号组合,将其添加到结果列表中。
- 如果
-
递归过程:
- 如果
open < max
,表示左括号还可以继续添加,递归调用backtrack(current + "(", open + 1, close, max)
。 - 如果
close < open
,表示右括号的数量少于左括号,可以继续添加右括号,递归调用backtrack(current + ")", open, close + 1, max)
。
- 如果
通过这种方式,我们能确保生成的所有组合都是有效的括号组合。
代码实现
import java.util.ArrayList;
import java.util.List;
public class GenerateParentheses {
List<String> combinations = new ArrayList<>();
public List<String> generateParenthesis(int n) {
// 调用回溯函数开始生成括号组合
backtrack("", 0, 0, n);
// 返回生成的括号组合列表
return combinations;
}
private void backtrack(String current, int open, int close, int max) {
// 如果当前字符串长度等于最大括号数的两倍,说明已经生成了一个完整的括号组合
if (current.length() == 2 * max) {
// 将当前括号组合添加到结果列表中
combinations.add(current);
return;
}
// 如果左括号数量小于最大括号数
if (open < max) {
// 递归调用回溯函数,添加左括号,并更新左括号和右括号的数量
backtrack(current + "(", open + 1, close, max);
}
// 如果右括号数量小于左括号数量
if (close < open) {
// 递归调用回溯函数,添加右括号,并更新左括号和右括号的数量
backtrack(current + ")", open, close + 1, max);
}
}
public static void main(String[] args) {
GenerateParentheses g = new GenerateParentheses();
System.out.println(g.generateParenthesis(3));
}
}
代码解析
-
初始化与回溯调用:
- 我们在
generateParenthesis(int n)
方法中初始化了一个存储结果的列表combinations
,并调用backtrack
函数开始回溯生成括号组合。
- 我们在
-
递归生成括号组合:
backtrack
方法负责递归生成所有有效的括号组合。通过判断左括号和右括号的使用情况,动态生成括号组合。
-
终止条件与添加结果:
- 当生成的括号组合达到指定长度(
2 * n
)时,说明一个有效的组合已经完成,将其加入到combinations
列表中。
- 当生成的括号组合达到指定长度(
-
打印结果:
- 在
main
方法中,我们实例化GenerateParentheses
类并调用generateParenthesis(3)
方法,输出结果。
- 在
总结
通过这篇文章,我们学习了如何使用回溯算法来生成有效的括号组合,并理解了递归算法在解决类似问题中的应用。回溯算法的思路在于探索所有可能的解,并通过条件筛选出有效的解。通过回溯算法,很多复杂问题都能找到有效的解决方案。