想刷刷leetcode鍛鍊寫自己寫程式碼的能力,關於寫程式碼,我覺得它不僅僅是寫程式碼,而是寫你的想法。為什麼有的人會寫成一坨,而有的人程式碼工整,美感,這個一方面是一個人寫之前是否有思考清楚,另外一方面是寫程式碼的習慣了。
程式碼只是表達思想的一種
題目
給出 n 代表生成括號的對數,請你寫出一個函式,使其能夠生成所有可能的並且有效的括號組合。
例如,給出 n = 3,生成結果為:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ] 複製程式碼
解題
首先想到的是,每一個位置都有兩種可能性:2^6 = 64。
- 有一些很明顯就錯誤的,比如:"((( ((("
- 排除顯而易見錯誤的,即左括號與右括號數量不等的
- 有錯誤不是那麼明顯看出來的,比如:"))) (((" , "()) (()"
- 開頭是右括號的,直接去掉,這個其實代表右括號已經出現的數量大於左括號出現的數量
正確的方案是,首先要放入左括號"(",後續要有一個與之對應的括號,同時在任何位置,有括號")"的數量不能大於"("的數量,否則,"())" 就是錯誤的。
程式碼
- 首先定義一個方法,要知道當前左括號與有括號的數量,並且知道當前的字串
/**
*
* @param left 代表當前已經出現的左括號數量
* @param right 代表當前已經出現的右括號數量
* @param n 代表生成括號的對數
* @param s 代表當前的字串,可能還未處理完
* @param res 儲存所有括號字串的列表
*/
private void generateParenthesis(int left, int right, int n, String s,List<String> res) {
}
複製程式碼
- 目前比較喜歡的debug方式為通過列印,來看程式碼是否符合自己的預期,另外這次寫一下終止條件
private void generateParenthesis(int left, int right, int n, String s,List<String> res) {
System.out.printf("當前的字串為:%s ,左:%d,右%d \n",s,left,right);
// 終止條件
if (left == n && right == n){
res.add(s);
return;
}
...
}
複製程式碼
- 中間的執行過程。首先要放入左括號,然後再放入有括號
private void generateParenthesis(int left, int right, int n, String s,List<String> res) {
System.out.printf("當前的字串為:%s ,左:%d,右%d \n",s,left,right);
// 終止條件
if (left == n && right == n){
res.add(s);
return;
}
// 保證首先新增的是左括號
if (left < n){
generateParenthesis(left+1,right,n,s + "(",res);
}
// 注意,這裡的right < left,代表的意思是
// 首先我們肯定要放入左括號才是合法的,這樣的話,任何時刻,左括號的數量只能比右括號的數量多
if (right < n && right < left){
generateParenthesis(left,right+1,n,s + ")",res);
}
}
複製程式碼
- 最終程式碼為
public class Solution_22 {
/**
* n = 3 生成
* [
* "((()))",
* "(()())",
* "(())()",
* "()(())",
* "()()()"
* ]
*
* 每一個位置都有兩種可能性:2^6 = 64。
* 有一些很明顯就錯誤的,比如:"((( ((("
* - 排除顯而易見錯誤的,即左括號與右括號數量不等的
* 有錯誤不是那麼明顯看出來的,比如:"))) (((" , "()) (()"
* - 開頭是右括號的,直接去掉,這個其實代表右括號已經出現的數量大於左括號出現的數量
*
* 正確的方案是首先放左括號,後面只需要有對應的右括號才行
*/
public static void main(String[] args) {
List<String> list = new Solution_22().generateParenthesis(3);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
public List<String> generateParenthesis(int n) {
if(n == 0){
return Collections.emptyList();
}
List res = new LinkedList<String>();
generateParenthesis(0,0,n,"",res);
return res;
}
/**
*
* @param left 代表當前已經出現的左括號數量
* @param right 代表當前已經出現的右括號數量
* @param n 代表生成括號的對數
* @param s 代表當前的字串,可能還未處理完
* @param res 儲存所有括號字串的列表
*/
private void generateParenthesis(int left, int right, int n, String s,List<String> res) {
System.out.printf("當前的字串為:%s ,左:%d,右%d \n",s,left,right);
// 終止條件
if (left == n && right == n){
res.add(s);
return;
}
// 保證首先新增的是左括號
if (left < n){
generateParenthesis(left+1,right,n,s + "(",res);
}
// 注意,這裡的right < left,代表的意思是
// 首先我們肯定要放入左括號才是合法的,這樣的話,任何時刻,左括號的數量只能比右括號的數量多
if (right < n && right < left){
generateParenthesis(left,right+1,n,s + ")",res);
}
}
}
複製程式碼
執行效果
最後
遞迴的程式碼有一個問題,一般不能執行太多的層數,否則會堆疊錯誤。