力扣 面試題 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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章