题目链接:N-Queens

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.

For example,

There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

这道题的要求是N皇后问题:放置n的皇后在n*n的棋盘上,使其任意两个皇后不能相互攻击。给定整数n,返回所有可能情况,其中‘Q’表示皇后,‘.’表示空位置。

两个皇后不能相互攻击,即要求这两个皇后不在同一行、同一列及同一斜线上。

N皇后问题,一道非常经典的问题,NP问题,主要思路就是采用递归不断处理子问题,和之前的Sudoku Solver问题类似。每次在棋盘上的当前行放置1个皇后,这需要在该行枚举所有情况,当不与前面行的皇后冲突时,就可以递归处理剩下位置。当当前行数超过最后一行的时候,保存结果,递归结束。

关键问题是如何检测在某行某列放置皇后的时候是否造成冲突。

  • 可以用一个n*n的数组作为标记,在放置一皇后的时候,将其对应行、列及斜线都置为不能放置皇后状态,这样在放下一皇后的时候,就可以直接判断该位置能否造成冲突。不过这样的空间复杂度比较高(O(n2))。
  • 其实,由于每一行只允许放置1个皇后,因此可以采用1个长度为n的整形数组记录每行放置皇后的位置,这样空间复杂度就降低为O(n)了。这时,在检查当前位置的皇后是否于之前的皇后冲突时,就需要遍历之前的皇后,以检测是否冲突。由于按行递归,因此已经限制了皇后都不在同一行,因此只需检测列值是否相同,以及行列差的绝对值是否相同(判断是否在同一斜线)。

时间复杂度:O(???)

空间复杂度:O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution
{
    vector<vector<string> > vvs;
    
public:
    vector<vector<string> > solveNQueens(int n)
    {
        vector<int> vi(n);
        solveNQueens(vi, n, 0);
        return vvs;
    }
    
private:
    void solveNQueens(vector<int> &vi, int n, int c)
    {
        if(c == n)
        {
            vector<string> vs(n, string(n, '.'));
            for(int i = 0; i < n; ++ i)
                vs[i][vi[i]] = 'Q';
            vvs.push_back(vs);
            return;
        }

        for(vi[c] = 0; vi[c] < n; ++ vi[c])
            if(safe(vi, n, c))
                solveNQueens(vi, n, c + 1);
    }

    bool safe(vector<int> &vi, int n, int c)
    {
        for(int i = 0; i < c; ++ i)
            if(vi[i] == vi[c] || abs(vi[c] - vi[i]) == abs(c - i))
                return false;
        return true;
    }
};