若是給出一個正整數,表示一共有多少對括號,如何輸出全部括號可能的組合?java
好比:給出的括號對數爲3, 則全部括號的組合有以下幾種:函數
()()() ()(()) (())() (()()) ((()))
爲了解決這個問題,本文采用兩種方式來完成。測試
接下來,咱們一塊兒來看看廣度優先搜索和深度優先搜索的思想和具體實現。spa
所謂廣度優先搜索的方式就是儘量早的先輸出完整的括號對(), 也就是當輸出一個左括號 '(' , 儘量先輸出一個右括號 ‘)’ 。code
好比要輸出括號對數是2對的全部可能,先輸出的結果是()(), 而不是(())。orm
()() (())
咱們能夠定義三個值來完成遞歸調用:遞歸
currParentheses 當前存放的括號組合狀況 leftCount 剩餘左括號數 rightCount 剩餘右括號數
何時輸出一個候選結果?io
當剩餘左括號數和剩餘右括號數都爲0的時候。form
左括號'('和右括號'')輸出的時機?class
廣度優先搜索的目的是先獲得完整的括號對(), 這種狀況下須要須要考慮以下兩種狀況:
有了上述的思想,咱們能夠很容易寫出相應的程序來。具體代碼以下:
/** * 廣度優先搜索遞歸函數 * @param currParentheses 當前存放的括號組合狀況 * @param leftCount 剩餘左括號數 * @param rightCount 剩餘右括號數 */ private void bfsRecu(String currParentheses, int leftCount, int rightCount) { /** * 結束條件: * 當剩餘括號數和剩餘右括號數都爲0時,表示括號已經用完,直接輸出就能夠打印出一種狀況 */ if (leftCount == 0 && rightCount == 0) { System.out.println(currParentheses); } /** * 廣度優先搜索的目的是先獲得完整的括號對(), 這種狀況下 * 須要檢查剩餘的右括號數是否大於剩餘的左括號數,若是大於則表示已經有一個左括號輸出了, * 在這種狀況下,將當前存放的括號組合狀況添加一個右括號,而後右邊括號數減1,而後遞歸調用 * */ if (rightCount > leftCount) { bfsRecu(currParentheses + ')', leftCount, rightCount - 1); } /** * 若是還有剩餘左括號數,則將當前存放的括號組合狀況添加一個左括號,而後剩餘左邊括號數減1,而後遞歸調用便可 */ if (leftCount > 0) { bfsRecu(currParentheses + '(', leftCount - 1, rightCount); } }
有了廣度優先搜索的遞歸調用函數,廣度優先搜索方法就能夠調用遞歸函數便可。當前存放括號內容的變量爲空。
/** * 廣度搜索方式打印括號組合數字 * @param parentheseCount 括號對數 */ public void bfs(int parentheseCount) { if (parentheseCount < 1) { throw new IllegalArgumentException("括號對數不能小於1"); } bfsRecu("", parentheseCount, parentheseCount); }
深度優先搜索的思路和廣度優先搜索相似,惟一的區別就是先輸出完整的括號對,仍是先儘量多地輸出左括號。
廣度優先搜索的方式就是儘量早的先輸出完整的括號對(), 也就是當輸出一個左括號 '(' , 儘量先輸出一個右括號 ‘)’ 。
深度優先搜索的方式就是儘量早的先輸出左括號('', 也就是若是剩餘左括號數大於0的時,先獲取左邊括號'('。
好比要輸出括號對數是2對的全部可能,先輸出的結果是(()), 而不是()()。
(()) ()()
和廣度優先搜索同樣,咱們依舊能夠定義三個值來完成遞歸調用:
currParentheses 當前存放的括號組合狀況 leftCount 剩餘左括號數 rightCount 剩餘右括號數
何時輸出一個候選結果?
當剩餘左括號數和剩餘右括號數都爲0的時候。
左括號'('和右括號'')輸出的時機?
深度優先搜索的目的是先儘量多的獲得左括號'(', 這種狀況下須要須要考慮以下兩種狀況:
有了上述的思想,咱們能夠很容易寫出相應的程序來。具體代碼以下:
/** * 深度優先搜索遞歸方法 * @param currParentheses 當前存放的括號組合狀況 * @param leftCount 剩餘左括號數 * @param rightCount 剩餘右括號數 */ private void dfsRecu(String currParentheses, int leftCount, int rightCount) { /** * 結束條件: * 當剩餘括號數和剩餘右括號數都爲0時,表示括號已經用完,直接輸出就能夠打印出一種狀況 */ if (leftCount == 0 && rightCount == 0) { System.out.println(currParentheses); } /** * 深度優先搜索的目的是儘量先獲取左邊括號, 這種狀況下, 若是剩餘左括號數大於0,則 * 將當前存放的括號組合狀況添加一個左括號,而後剩餘左邊括號數減1,而後遞歸調用 * */ if (leftCount > 0) { dfsRecu(currParentheses + '(', leftCount - 1, rightCount); } /** * 檢查剩餘的右括號數是否大於剩餘的左括號數,若是大於, * 則將當前存放的括號組合狀況添加一個右括號,而後右邊括號數減1,而後遞歸調用 * */ if (rightCount > leftCount) { dfsRecu(currParentheses + ')', leftCount, rightCount - 1); } }
有了深度優先搜索的遞歸調用函數,深度優先搜索方法就能夠調用遞歸函數便可。
/** * 深度搜索方式打印括號組合數字 * @param parentheseCount 括號對數 */ public void dfs(int parentheseCount) { if (parentheseCount < 1) { throw new IllegalArgumentException("括號對數不能小於1"); } dfsRecu("", parentheseCount, parentheseCount); }
/** * @author wangmengjun */ public class ParenthesesPrinter { /** * 廣度搜索方式打印括號組合數字 * @param parentheseCount 括號對數 */ public void bfs(int parentheseCount) { if (parentheseCount < 1) { throw new IllegalArgumentException("括號對數不能小於1"); } bfsRecu("", parentheseCount, parentheseCount); } /** * 廣度優先搜索遞歸函數 * @param currParentheses 當前存放的括號組合狀況 * @param leftCount 剩餘左括號數 * @param rightCount 剩餘右括號數 */ private void bfsRecu(String currParentheses, int leftCount, int rightCount) { /** * 結束條件: * 當剩餘括號數和剩餘右括號數都爲0時,表示括號已經用完,直接輸出就能夠打印出一種狀況 */ if (leftCount == 0 && rightCount == 0) { System.out.println(currParentheses); } /** * 廣度優先搜索的目的是先獲得完整的括號對(), 這種狀況下 * 須要檢查剩餘的右括號數是否大於剩餘的左括號數,若是大於則表示已經有一個左括號輸出了, * 在這種狀況下,將當前存放的括號組合狀況添加一個右括號,而後右邊括號數減1,而後遞歸調用 * */ if (rightCount > leftCount) { bfsRecu(currParentheses + ')', leftCount, rightCount - 1); } /** * 若是還有剩餘左括號數,則將當前存放的括號組合狀況添加一個左括號,而後剩餘左邊括號數減1,而後遞歸調用便可 */ if (leftCount > 0) { bfsRecu(currParentheses + '(', leftCount - 1, rightCount); } } /** * 深度搜索方式打印括號組合數字 * @param parentheseCount 括號對數 */ public void dfs(int parentheseCount) { if (parentheseCount < 1) { throw new IllegalArgumentException("括號對數不能小於1"); } dfsRecu("", parentheseCount, parentheseCount); } /** * 深度優先搜索遞歸方法 * @param currParentheses 當前存放的括號組合狀況 * @param leftCount 剩餘左括號數 * @param rightCount 剩餘右括號數 */ private void dfsRecu(String currParentheses, int leftCount, int rightCount) { /** * 結束條件: * 當剩餘括號數和剩餘右括號數都爲0時,表示括號已經用完,直接輸出就能夠打印出一種狀況 */ if (leftCount == 0 && rightCount == 0) { System.out.println(currParentheses); } /** * 深度優先搜索的目的是儘量先獲取左邊括號, 這種狀況下, 若是剩餘左括號數大於0,則 * 將當前存放的括號組合狀況添加一個左括號,而後剩餘左邊括號數減1,而後遞歸調用 * */ if (leftCount > 0) { dfsRecu(currParentheses + '(', leftCount - 1, rightCount); } /** * 檢查剩餘的右括號數是否大於剩餘的左括號數,若是大於, * 則將當前存放的括號組合狀況添加一個右括號,而後右邊括號數減1,而後遞歸調用 * */ if (rightCount > leftCount) { dfsRecu(currParentheses + ')', leftCount, rightCount - 1); } } }
/** * @author wangmengjun * */ public class Main { public static void main(String[] args) { ParenthesesPrinter example = new ParenthesesPrinter(); for (int i = 2; i <= 5; i++) { System.out.println(String.format("廣度優先搜索, %d對括號全部的可能組合,", i)); example.bfs(i); System.out.println(); System.out.println(String.format("深度優先搜索, %d對括號全部的可能組合,", i)); example.dfs(i); System.out.println(); } } }
運行結果以下:
廣度優先搜索, 2對括號全部的可能組合, ()() (()) 深度優先搜索, 2對括號全部的可能組合, (()) ()() 廣度優先搜索, 3對括號全部的可能組合, ()()() ()(()) (())() (()()) ((())) 深度優先搜索, 3對括號全部的可能組合, ((())) (()()) (())() ()(()) ()()() 廣度優先搜索, 4對括號全部的可能組合, ()()()() ()()(()) ()(())() ()(()()) ()((())) (())()() (())(()) (()())() (()()()) (()(())) ((()))() ((())()) ((()())) (((()))) 深度優先搜索, 4對括號全部的可能組合, (((()))) ((()())) ((())()) ((()))() (()(())) (()()()) (()())() (())(()) (())()() ()((())) ()(()()) ()(())() ()()(()) ()()()() 廣度優先搜索, 5對括號全部的可能組合, ()()()()() ()()()(()) ()()(())() ()()(()()) ()()((())) ()(())()() ()(())(()) ()(()())() ()(()()()) ()(()(())) ()((()))() ()((())()) ()((()())) ()(((()))) (())()()() (())()(()) (())(())() (())(()()) (())((())) (()())()() (()())(()) (()()())() (()()()()) (()()(())) (()(()))() (()(())()) (()(()())) (()((()))) ((()))()() ((()))(()) ((())())() ((())()()) ((())(())) ((()()))() ((()())()) ((()()())) ((()(()))) (((())))() (((()))()) (((())())) (((()()))) ((((())))) 深度優先搜索, 5對括號全部的可能組合, ((((())))) (((()()))) (((())())) (((()))()) (((())))() ((()(()))) ((()()())) ((()())()) ((()()))() ((())(())) ((())()()) ((())())() ((()))(()) ((()))()() (()((()))) (()(()())) (()(())()) (()(()))() (()()(())) (()()()()) (()()())() (()())(()) (()())()() (())((())) (())(()()) (())(())() (())()(()) (())()()() ()(((()))) ()((()())) ()((())()) ()((()))() ()(()(())) ()(()()()) ()(()())() ()(())(()) ()(())()() ()()((())) ()()(()()) ()()(())() ()()()(()) ()()()()()