原题地址(困难)

方法1—回溯

思路

赫赫有名的八皇后问题的变种。
其实这题不是很难,就是最基础的回溯解法。但是要剪枝,也就是每次都要判断第i行第j列是否可以放置皇后,即判断(i, j)位置是否满足行不重复、列不重复、主对角线方向不重复、副对角线方向不重复。

行和列我们肯定非常容易判断,我们按行遍历回溯,行就不需要判断了,列的话用一个一维vector来存储就好了,被占用了第k列,就记 column[k] = 1
至于主对角线方向不重复、副对角线方向,其实和列一样,各用一个一维vector来判断就可以,只不过需要你找出一些规则。

盗用一些官方的图
首先明确,无论主对角线还是副对角线方向,数组大小都是2*n+1
image.png
我们定义主对角线方向的数组为 a ,从右上角到左下角,下标依次为 0, 1, ..., 2n-1
a[0] 对应图中的一个位置,就是(0, 7)
a[1] 对应两个位置,就是(0, 6) , (1, 7)
…..
a[2n-1] 对应一个位置,就是(7, 0)
我们可以发现,同一列中,行值越大,在a中越靠后;同一行中,列值越大,在a中越靠前。所以对应公式中一定有 i-j
通过尝试,发现最终公式为: i+(n-1)-j ,即 (i, j) 对应 a[i+n-1-j]
**
image.png
同理得到副对角线方向的对应公式: i+j

代码

  1. class Solution {
  2. public:
  3. vector<int> a, b, column;
  4. vector<string> v;
  5. vector<vector<string>> ans;
  6. vector<vector<string>> solveNQueens(int n) {
  7. // 主对角线方向,副对角线方向,列方向
  8. a.resize(2*n+1, 0);
  9. b.resize(2*n+1, 0);
  10. column.resize(n, 0);
  11. dfs(0, n);
  12. return ans;
  13. }
  14. void dfs(int row, int n) {
  15. if(row == n){
  16. ans.push_back(v);
  17. return;
  18. }
  19. // 对第row行的每一列
  20. for(int j=0; j<n; j++){
  21. //如果(row, j)这个位置满足行列左斜右斜都没有重复皇后
  22. if(!a[row+n-1-j] && !b[row+j] && !column[j]){
  23. a[row+n-1-j] = b[row+j] = column[j] = 1;
  24. string s(n, '.');
  25. s[j] = 'Q';
  26. v.push_back(s);
  27. dfs(row+1, n);
  28. v.pop_back();
  29. a[row+n-1-j] = b[row+j] = column[j] = 0;
  30. }
  31. }
  32. return;
  33. }
  34. };

时空复杂度

时间复杂度 O(N!)
空间复杂度 O(2N+1)

方法2—

思路

代码

时空复杂度