輸出指定括號對數的全部可能組合

若是給出一個正整數,表示一共有多少對括號,如何輸出全部括號可能的組合?java

好比:給出的括號對數爲3, 則全部括號的組合有以下幾種:函數

()()()
()(())
(())()
(()())
((()))

爲了解決這個問題,本文采用兩種方式來完成。測試

  • 廣度優先搜索的方式
  • 深度優先搜索的方式

接下來,咱們一塊兒來看看廣度優先搜索深度優先搜索的思想和具體實現。spa

廣度優先搜索方式

思想

所謂廣度優先搜索的方式就是儘量早的先輸出完整的括號對(), 也就是當輸出一個左括號 '(' , 儘量先輸出一個右括號 ‘)’ 。code

好比要輸出括號對數是2對的全部可能,先輸出的結果是()(), 而不是(())orm

()()
(())

 

咱們能夠定義三個值來完成遞歸調用:遞歸

currParentheses 當前存放的括號組合狀況
leftCount 剩餘左括號數
rightCount 剩餘右括號數

 

何時輸出一個候選結果?io

剩餘左括號數和剩餘右括號數都爲0的時候。form

左括號'('和右括號'')輸出的時機?class

廣度優先搜索的目的是先獲得完整的括號對(), 這種狀況下須要須要考慮以下兩種狀況:

  • 輸出右邊括號')'的時機:若是剩餘的右括號數大於剩餘的左括號數,那麼意味着以前已經有一個左括號輸出了,在這種狀況下,將當前存放的括號組合狀況添加一個右括號,而後剩餘右邊括號數減1,而後繼續遞歸調用。
  • 輸出左邊括號'('的時機:若是剩餘的左括號數leftCount大於0,則當前存放的括號組合狀況添加一個左括號'(', 而後剩餘左括號數減1,而後繼續遞歸調用。

有了上述的思想,咱們能夠很容易寫出相應的程序來。具體代碼以下:

代碼實現

/**
     * 廣度優先搜索遞歸函數
     * @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的時候。

左括號'('和右括號'')輸出的時機?

深度優先搜索的目的是先儘量多的獲得左括號'(', 這種狀況下須要須要考慮以下兩種狀況:

  • 輸出左邊括號'('的時機:若是剩餘的左括號數leftCount大於0,則當前存放的括號組合狀況添加一個左括號'(', 而後剩餘左括號數減1,而後繼續遞歸調用。
  • 輸出右邊括號')'的時機:若是剩餘的右括號數大於剩餘的左括號數,那麼意味着以前已經有一個左括號輸出了,在這種狀況下,將當前存放的括號組合狀況添加一個右括號,而後剩餘右邊括號數減1,而後繼續遞歸調用。

有了上述的思想,咱們能夠很容易寫出相應的程序來。具體代碼以下:

代碼實現

/**
     * 深度優先搜索遞歸方法
     * @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對括號全部的可能組合,
((((()))))
(((()())))
(((())()))
(((()))())
(((())))()
((()(())))
((()()()))
((()())())
((()()))()
((())(()))
((())()())
((())())()
((()))(())
((()))()()
(()((())))
(()(()()))
(()(())())
(()(()))()
(()()(()))
(()()()())
(()()())()
(()())(())
(()())()()
(())((()))
(())(()())
(())(())()
(())()(())
(())()()()
()(((())))
()((()()))
()((())())
()((()))()
()(()(()))
()(()()())
()(()())()
()(())(())
()(())()()
()()((()))
()()(()())
()()(())()
()()()(())
()()()()()
相關文章
相關標籤/搜索