【LeetCode】51. N 皇后

一、题目

n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
queens
上图为 8 皇后问题的一种解法。

给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。

示例:

输入:4
输出:[
 [".Q..",  // 解法 1
  "...Q",
  "Q...",
  "..Q."],
 ["..Q.",  // 解法 2
  "Q...",
  "...Q",
  ".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。

提示:

  • 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

二、解决

1、DFS

版本1

思路:
给定一个N*N方格Grid,从Grid[0,0]开始,逐行向下扫描,若一行中某个格子存在合法的位置,记录下来,然后继续往下扫描。

中间有不合法格子则中断,回到上一层的后一个格子,然后再逐层往下扫描,扫描到最后一行后,若存在合法的位置,则记录下来。

下面是一个4*4的回溯状态树,来自参考5,具体回溯过程可以观看其中的视频,比较详细。
结果

代码:

public List<List<String>> solveNQueens(int n) {
    
    
	List<List<String>> res = new LinkedList<List<String>>();
	int[] usedCols = new int[n];// usedCols[i]: Column of the queen in row i
	Arrays.fill(usedCols, -1);  // 数组usedCols每个元素都填上-1
	DFS(usedCols, 0, res);
	return res;
}

void DFS(int[] usedCols, int row, List<List<String>> res) {
    
    
	int n = usedCols.length;
	if (row == n) {
    
    
		res.add(drawGrids(usedCols));
		return;
	}

	// 扫描当前行的每一列
	for (int col = 0; col < n; col++) {
    
    
		// 对该格进行判断,有效则记录并继续扫描下一行
		if (isValid(usedCols, row, col)) {
    
    
			usedCols[row] = col;
			DFS(usedCols, row + 1, res);// Move on to the next row
		}
	}
}

// Check if the column is valid to place queen for the row.
boolean isValid(int[] usedCols, int row, int col) {
    
    
	for (int i = 0; i < row; i++) {
    
    
		// 检查前面使用的行是否影响该格 (row, col)
		//                    ==> x0  - x ==      abs(y0  -  y)
		if (usedCols[i] == col || row - i == Math.abs(col - usedCols[i]))    			
			return false;
	}
	return true;
}

List<String> drawGrids(int[] usedCols) {
    
    
	List<String> res = new LinkedList<>();
	for (int i : usedCols) {
    
    
    	char[] line = new char[usedCols.length];
    	Arrays.fill(line, '.');
    	line[i] = 'Q';
    	res.add(String.valueOf(line));
	}
	return res;
}

时间复杂度: O ( n ! ) O(n!) O(n!),n为皇后数量。
空间复杂度: O ( n ) O(n) O(n)

版本2

思路: 同版本1.
代码:

class Solution {
    
    

    private Set<Integer> cols = new HashSet<>();
    private Set<Integer> diag1 = new HashSet<>();
    private Set<Integer> diag2 = new HashSet<>();

    public List<List<String>> solveNQueens(int n) {
    
    
        List<String> resUnit = new LinkedList<>();
        List<List<String>> res = new LinkedList<>();
        DFS(0, n, resUnit, res);
        return res;
    }

    private void DFS(int row, int n, List<String> resUnit, List<List<String>> res) {
    
    
        if (row==n) {
    
    
            res.add(new ArrayList<>(resUnit));
            return;
        }

        for(int col=0; col<n; col++) {
    
    
            if (cols.contains(col) || diag1.contains(row+col) || diag2.contains(row-col))  continue;

            char[] line = new char[n];
            Arrays.fill(line, '.');
            line[col] = 'Q';

            resUnit.add(String.valueOf(line));
            cols.add(col);
            diag1.add(row+col);
            diag2.add(row-col);

            DFS(row+1, n, resUnit, res);

            resUnit.remove(resUnit.size()-1);
            cols.remove(col);
            diag1.remove(row+col);
            diag2.remove(row-col);
        }
    }
}

时间复杂度: O ( n ! ) O(n!) O(n!)
空间复杂度: O ( n ) O(n) O(n)

版本3

思路: 同版本1。
代码:

class Solution {
    
    

    boolean[] cols;
    boolean[] diag1;
    boolean[] diag2;

    public List<List<String>> solveNQueens(int n) {
    
    

        cols = new boolean[n];
        diag1 = new boolean[2*n];
        diag2 = new boolean[2*n];
        List<String> resUnit = new ArrayList<>();
        List<List<String>> res = new ArrayList<>();
        DFS(0, n, resUnit, res);
        return res;
    }

    private void DFS(int row, int n, List<String> resUnit, List<List<String>> res) {
    
    
        if (row==n) {
    
    
            res.add(new ArrayList<>(resUnit));
            return;
        }
        for (int col=0; col<n; col++) {
    
    
            if (cols[col] || diag1[row+col] || diag2[row-col+n])  continue;

            char[] line = new char[n];
            Arrays.fill(line, '.');
            line[col] = 'Q';
            
            resUnit.add(new String(line));
            cols[col]=true; diag1[row+col]=true; diag2[row-col+n]=true;

            DFS(row+1, n, resUnit, res);

            resUnit.remove(resUnit.size()-1);
            cols[col]=false; diag1[row+col]=false; diag2[row-col+n]=false;
        }
    }
}

时间复杂度: O ( n ! ) O(n!) O(n!)
空间复杂度: O ( n ) O(n) O(n)

三、参考

1、Concise JAVA solution based on DFS
2、My easy understanding Java Solution
3、Comparably concise Java code
4、Share my JAVA DFS solution very easy to understand
5、回溯算法(转换成全排列问题 + 剪枝)- 题解后有相关问题
6、N皇后
7、java中数组的初始化(Arrays.fill() )
8、java中String数组和List的互相转化

猜你喜欢

转载自blog.csdn.net/HeavenDan/article/details/108562501