leetcode51(N皇后:回溯法)

tech2025-04-21  6

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。

每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例: 输入:4 输出:[ [".Q…", // 解法 1 “…Q”, “Q…”, “…Q.”],

["…Q.", // 解法 2 “Q…”, “…Q”, “.Q…”] ] 解释: 4 皇后问题存在两个不同的解法。

题解:利用回溯法遍历所有可能的情况,找出满足要求的情况,为了降低时间复杂度,我们可以在遍历的同时增加一些条件限制——每当我们在一个位置上放置了一个皇后时,我们可以将左斜线,右斜线,竖直方向和横向方向设置为“禁区”,即不能放皇后的位置,同时为了方便回溯,我们以横行为单位,从上到下的放置皇后,每一行放一个(由于n个皇后放置在n ∗ * n的棋盘上,所以必定每一行放一个)。

import java.util.*; class Solution { private final Stack<Integer>stack=new Stack<>(); private final List<List<String>>res=new ArrayList<>(); public List<List<String>> solveNQueens(int n) { //二维布尔型数组记录不能放置皇后的位置 boolean[][] banned=new boolean[n][n]; DFS(banned,0); return res; } private void DFS(boolean[][]banned,int row){ if(stack.size()== banned.length){ getMap(stack,res); return; } Queue<int[]>save=new LinkedList<>(); int len=banned[row].length; //在每一行从左到右一次尝试放皇后 for(int i=0;i<len;i++){ if(!banned[row][i]) { stack.add(i); //将该行往下的每一行不能放置皇后的位置都设置为true for (int j = row; j < banned.length; j++) { if(!banned[j][i ]) { save.add(new int[]{j, i}); banned[j][i] = true; } int k = j - row; if (i + k < len&&!banned[j][i + k]) { save.add(new int[]{j, i + k}); banned[j][i + k] = true; } if (i - k >= 0&&!banned[j][i - k]) { save.add(new int[]{j, i - k}); banned[j][i - k] = true; } } DFS(banned, row + 1); stack.pop(); //还原 while(!save.isEmpty()){ int[] temp=save.poll(); banned[temp[0]][temp[1]]=false; } } } } private void getMap(Stack<Integer>stack,List<List<String>>res){ int size=stack.size(); List<String>map=new ArrayList<>(); for(int x:stack){ StringBuilder row=new StringBuilder(); for(int i=0;i<size;i++){ if(i!=x) row.append("."); else row.append("Q"); } map.add(row.toString()); } res.add(map); } }

优化:我们可以通过棋盘的规律优化代码——其实棋盘上的每一条斜线都有一个该斜线独有的数字,比如同一条右斜线上的点横纵坐标的差为一个特有的常数,左斜线上的点横纵坐标上的和为一个特有常数,同时不同列可以用列标数字进行区分,所以,我们不必再用二维数组来保存不能放置皇后的点,直接用一个数字来代表某条斜线上或某列上不能放置皇后。

import java.util.*; class Solution { private final Stack<Integer>stack=new Stack<>(); private final List<List<String>>res=new ArrayList<>(); private final Set<Integer>left=new HashSet<>(); private final Set<Integer>right=new HashSet<>(); private final Set<Integer>down=new HashSet<>(); public List<List<String>> solveNQueens(int n) { boolean[][] banned=new boolean[n][n]; backTrace(0,n); return res; } private void backTrace(int column,int len){ if(stack.size()==len){ getMap(stack,res); return; } for(int i=0;i<len;i++){ int rightKey=column-i; int leftKey=column+i; if(!right.contains(rightKey)&&!left.contains(leftKey)&&!down.contains(i)) { right.add(rightKey); left.add(leftKey); down.add(i); stack.push(i); backTrace(column+1,len); right.remove(rightKey); left.remove(leftKey); down.remove(i); stack.pop(); } } } private void getMap(Stack<Integer>stack,List<List<String>>res){ int size=stack.size(); List<String>map=new ArrayList<>(); for(int x:stack){ StringBuilder row=new StringBuilder(); for(int i=0;i<size;i++){ if(i!=x) row.append("."); else row.append("Q"); } map.add(row.toString()); } res.add(map); } }
最新回复(0)