输出指定括号对数的全部可能组合

若是给出一个正整数,表示一共有多少对括号,如何输出全部括号可能的组合?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对括号全部的可能组合,
((((()))))
(((()())))
(((())()))
(((()))())
(((())))()
((()(())))
((()()()))
((()())())
((()()))()
((())(()))
((())()())
((())())()
((()))(())
((()))()()
(()((())))
(()(()()))
(()(())())
(()(()))()
(()()(()))
(()()()())
(()()())()
(()())(())
(()())()()
(())((()))
(())(()())
(())(())()
(())()(())
(())()()()
()(((())))
()((()()))
()((())())
()((()))()
()(()(()))
()(()()())
()(()())()
()(())(())
()(())()()
()()((()))
()()(()())
()()(())()
()()()(())
()()()()()
相关文章
相关标签/搜索