题目描述(困难难度)

51. N-Queens - 图1

经典的 N 皇后问题。意思就是摆皇后的位置,每行每列以及对角线只能出现 1 个皇后。输出所有的情况。

解法一 回溯法

比较经典的回溯问题了,我们需要做的就是先在第一行放一个皇后,然后进入回溯,放下一行皇后的位置,一直走下去,如果已经放的皇后的数目等于 n 了,就加到最后的结果中。然后再回到上一行,变化皇后的位置,然后去找其他的解。

期间如果遇到当前行所有的位置都不能放皇后了,就再回到上一行,然后变化皇后的位置。再返回到下一行。

说起来可能还费力些,直接看代码吧。

  1. public List<List<String>> solveNQueens(int n) {
  2. List<List<String>> ans = new ArrayList<>();
  3. backtrack(new ArrayList<Integer>(), ans, n);
  4. return ans;
  5. }
  6. private void backtrack(List<Integer> currentQueen, List<List<String>> ans, int n) {
  7. // 当前皇后的个数是否等于 n 了,等于的话就加到结果中
  8. if (currentQueen.size() == n) {
  9. List<String> temp = new ArrayList<>();
  10. for (int i = 0; i < n; i++) {
  11. char[] t = new char[n];
  12. Arrays.fill(t, '.');
  13. t[currentQueen.get(i)] = 'Q';
  14. temp.add(new String(t));
  15. }
  16. ans.add(temp);
  17. return;
  18. }
  19. //尝试每一列
  20. for (int col = 0; col < n; col++) {
  21. //当前列是否冲突
  22. if (!currentQueen.contains(col)) {
  23. //判断对角线是否冲突
  24. if (isDiagonalAttack(currentQueen, col)) {
  25. continue;
  26. }
  27. //将当前列的皇后加入
  28. currentQueen.add(col);
  29. //去考虑下一行的情况
  30. backtrack(currentQueen, ans, n);
  31. //将当前列的皇后移除,去判断下一列
  32. //进入这一步就是两种情况,下边的行走不通了回到这里或者就是已经拿到了一个解回到这里
  33. currentQueen.remove(currentQueen.size() - 1);
  34. }
  35. }
  36. }
  37. private boolean isDiagonalAttack(List<Integer> currentQueen, int i) {
  38. // TODO Auto-generated method stub
  39. int current_row = currentQueen.size();
  40. int current_col = i;
  41. //判断每一行的皇后的情况
  42. for (int row = 0; row < currentQueen.size(); row++) {
  43. //左上角的对角线和右上角的对角线,差要么相等,要么互为相反数,直接写成了绝对值
  44. if (Math.abs(current_row - row) == Math.abs(current_col - currentQueen.get(row))) {
  45. return true;
  46. }
  47. }
  48. return false;
  49. }

时间复杂度:

空间复杂度:

上边我们只判断了列冲突和对角线冲突,至于行冲突,由于我们采取一行一行加皇后,所以一行只会有一个皇后,不会产生冲突。

最早接触的一类问题了,学回溯法的话,一般就会以这个为例,所以思路上不会遇到什么困难。

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情