今天是2020年4月9日,每日一題的第五天。
題目描述
數字 n 代表生成括號的對數,請你設計一個函數,用於能夠生成所有可能的並且 有效的 括號組合。
示例:
輸入:n = 3
輸出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
題目分析
參考liweiwei1419的題解(https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/),可以使用深度優先 + 遞歸的思想(回溯+剪枝)。
畫圖以後,可以分析出的結論:
- 當前左右括號都有大於 0 個可以使用的時候,才產生分支;
- 產生左分支的時候,只看當前是否還有左括號可以使用;
- 產生右分支的時候,還受到左分支的限制,右邊剩餘可以使用的括號數量一定得在嚴格大於左邊剩餘的數量的時候,纔可以產生分支;
- 在左邊和右邊剩餘的括號數都等於 0 的時候結算
在liweiwei的題解中還提供了使用廣度優先算法和動態規劃的方式解決這個問題,大家也可以仔細去研讀一下,也是很優秀的解法。
參考代碼
public class GenerateParenthesis {
List<String> result = Lists.newArrayList();
/**
* 遞歸生成
*
* @param n
* @return
*/
public List<String> generateParenthesis(int n) {
if (n == 0) {
return result;
}
if (n == 1) {
result.add("()");
return result;
}
dfs(n, n, "");
return result;
}
/**
* 通過暴力搜索,就是通過dfs。但是並不是每一個結果都符合要求,所以通過if來進行剪枝
*
* @param left
* @param right
* @param currentString
*/
private void dfs(int left, int right, String currentString) {
// 左右括號都不剩餘了,遞歸終止
if (left == 0 && right == 0) {
result.add(currentString);
return;
}
// 如果左括號還剩餘的話,可以拼接左括號,這裏是一個剪枝的過程。
if (left > 0) {
dfs(left - 1, right, currentString + "(");
}
// 如果右括號剩餘多於左括號剩餘的話,可以拼接右括號
if (right > left) {
dfs(left, right - 1, currentString + ")");
}
}
}