力扣 面试题 08.12. 八皇后(回溯&&剪枝&&深度搜索)

设计一种算法,打印 N皇后在 N × N棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。

注意:本题相对原题做了扩展

示例:

 输入:4
 输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
 解释: 4 皇后问题存在如下两个不同的解法。
[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]

思路:

  • 对于这种全部排列的问题,显然是回溯法。
  • 回溯法就是一棵决策树。
  • 通过循环中的条件判断进行剪枝。
  • 八皇后每一行、每一列、每一条对角线都只能有一个Q(皇后)。
  • 本题扩展到了N皇后。

伪代码如下:

行 = 0;
从第一列开始:
	如果这个点不合法:跳过。
	否则:
		本点放个皇后;
		回溯(下一行);
		撤销选择,删掉本点的皇后。

boolean 是否合法:
	判断此列是否有皇后;
	判断左上对角线是否有皇后;
	判断右上对角线是否有皇后;
	返回判断结果。

代码:

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<>();
        //定义棋盘
        char[][] qipan = new char[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                qipan[i][j] = '.';
            }
        }
        //从第0行开始回溯
        back_track(result,qipan,0,n);
        return result;
    }

    public void back_track(List<List<String>> result,char[][] qipan, int hang, int n){
        //如果到了最后一行,就结束本轮。
        if(hang == n){
            List<String> tmp = new ArrayList<>();
            for (int i1 = 0; i1 < n; i1++) {
                StringBuilder s = new StringBuilder();
                for (int i = 0; i < n; i++) {
                    s.append(qipan[i1][i]);
                }
                tmp.add(s.toString());
            }
            result.add(tmp);
            return;
        }

        //遍历选择
        for(int lie = 0; lie<n;lie++){
            //判断本位置是否合法,剪枝
            if(!isValid(qipan,hang,lie,n)) continue;
            //做选择
            qipan[hang][lie] = 'Q';
            //递归给下一行赋值
            back_track(result,qipan,hang+1,n);
            //撤销选择
            qipan[hang][lie] = '.';
        }
    }

    public boolean isValid(char[][] qipan, int hang, int lie, int n){
        //当前列不能有Q
//        for (int i = 0; i < n; i++) {
//            //判断第hang行的n列
//            if(qipan[hang][i] == 'Q') return false;
//        }
        for (int i = 0; i < n; i++) {
            //判断第lie行的n行
            if (qipan[i][lie] == 'Q') return false;
        }
        //左上角不能有Q
        //l是左侧位置,u是上方。
        int l = lie - 1;
        int u = hang - 1;
        while(l>=0 && u>=0){
            if(qipan[u][l] == 'Q') return false;
            l--;
            u--;
        }
        //右上角不能有Q
        //l是左侧位置,u是上方。
        int r = lie + 1;
        u = hang - 1;
        while(r<n && u>=0){
            if(qipan[u][r] == 'Q') return false;
            r++;
            u--;
        }
        return true;
    }
}

你可能感兴趣的:(LeetCode,Java)