1. 程式人生 > >【LeetCode】103.N-Queens

【LeetCode】103.N-Queens

題目描述(Hard)

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.

Each solution contains a distinct board configuration of the n

-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

題目連結

https://leetcode.com/problems/n-queens/description/

Example 1:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

演算法分析

設定一個數組vector<int>C(n, 0), C[i]表示第i行皇后所在的列編號,即在位置(i, C[i])上放了一個皇后,這樣用一個一維陣列就能記錄整個棋盤。

方法一:對當前行,每次逐列掃描,判斷所在位置是否放置皇后(前面的行的皇后是否衝突),判斷條件,對第i行: 1.是否在同一列C[i]==col;2.是否在同一對角線abs(row-i)==abs(col-C[i]),即兩點不構成正方形,就不在一條對角線上。時間複雜度O(n!*n),空間複雜度O(n)

方法二:記錄皇后已經佔據的列,佔據的主對角線、副對角線,對N×N的棋盤,主對角線和副對角線各2N-1條。對第row行,第i列資料,其所在主對角線位置為row-j+N-1,其所在副對角線的位置為row+j。時間複雜度O(n!)

,空間複雜度O(n)

提交程式碼(方法一):

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> result;
        vector<int> C(n, -1);
        dfs(result, C, 0);
        return result;
    }
    
    void dfs(vector<vector<string>> &result, vector<int> &C, int row) {
        const int N = C.size();
        if (row == N) {
            vector<string> solution;
            for (int i = 0; i < N; ++i) {
                string S(N, '.');
                S[C[i]] = 'Q';
                solution.push_back(S);
            }
            result.push_back(solution);
            return;
        }
        
        // 逐列掃描
        for (int i = 0; i < N; ++i) {
            if (!isValid(C, row, i)) continue;
            C[row] = i; 
            dfs(result, C, row + 1);
            C[row] = -1;
        }
    }
    
    bool isValid(vector<int>& C, int row, int col) {
        for (int i = 0; i < row; ++i) {
            // 如果在相同列
            if (C[i] == col) return false;
            // 在對角線上
            if (abs(row - i) == abs(col - C[i])) return false;
        }
        
        return true;
    }
    
};

提交程式碼(方法二):

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        columns = vector<bool>(n, false);
        main_diag = vector<bool>(2 * n - 1, false);
        anti_diag = vector<bool>(2 * n - 1, false);
        vector<vector<string>> result;
        vector<int> C(n, -1);
        dfs(result, C, 0);
        return result;
    }
private:
    vector<bool> columns;
    vector<bool> main_diag;
    vector<bool> anti_diag;
    void dfs(vector<vector<string>> &result, vector<int> &C, int row) {
        const int N = C.size();
        if (row == N) {
            vector<string> solution;
            for (int i = 0; i < N; ++i) {
                string S(N, '.');
                S[C[i]] = 'Q';
                solution.push_back(S);
            }
            result.push_back(solution);
            return;
        }
        
        // 逐列掃描
        for (int i = 0; i < N; ++i) {
            bool valid =  !columns[i] && !main_diag[row - i + N - 1]
                && !anti_diag[row + i];
            if (!valid) continue;
            columns[i] = main_diag[row - i + N - 1] 
                = anti_diag[row + i] = true;
            C[row] = i; 
            dfs(result, C, row + 1);
            C[row] = -1;
            columns[i] = main_diag[row - i + N - 1] 
                = anti_diag[row + i] = false;
        }
    }
};