[Leetcode]N-Queens

来源:互联网 发布:首轮融资知乎 编辑:程序博客网 时间:2024/06/08 14:22

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.."]]


首先要科普下在西洋棋中queen的角色。对于小时候玩过西洋棋后来就忘光的我来说,看到题目我真的不明白什么叫Queen attack each other。


Queen这个棋子只能竖着来,或者横着来,或者斜着来。基本可以把它理解为愣头青。所以要保证没有任何两个Queen相互攻击,就需要同时满足任意一行或一列不能出现两个Queen,任意一条斜线上也不能出现两个Queen。因此,考虑最基本的方法就是去遍历这个n*n的棋盘,看看如何摆放这n个Queen可以满足要求。


那么如何去遍历呢,想到一种直观的方法。用一个长为n整数数组int[] loc表示棋盘上Queen的位置。具体来说,res的每个元素的index表示表示所处的行,而该index中的值表示改行Queen所在的位置。例如loc[0] = 5表示第0行Queen在第5列。这样的数据结构可以保证任何一行只有一个Queen,因此我们只需要再保证这个Queen所在列和斜线上没有其他Queen,就能说明这个Queen是合法的。利用深度优先算法,不断深入遍历每一行,即,如果当前行中Queen所处位置合法,就递归的遍历下一行,检查是否合法。若所有行均合法,则返回。算法伪代码如下:


main_function(n) : 

初始化loc[n]

初始化结果集res

dfs(res, loc, 0, n)

return res


dfs(res,loc,row,n)

if row ==  n:

    return 

else

    for i in n:

        loc[row] = i

        if loc[row]合法:

             dfs(res,loc,row+1,n)


根据以上伪代码,Java代码实现如下:

public class Solution {    public List<String[]> solveNQueens(int n) {        ArrayList<String[]> res = new ArrayList<String[]>();        int[] loc = new int[n];//loc表示皇后所在位置,其每一个元素代表一行。比如loc = {1,3,2,0}表示在第一行,皇后在第一列,在第二行,皇后在第3列,以此类推。        dfs(res, loc, 0, n);//从第0行开始深度优先搜索        return res;    }        private void dfs(ArrayList<String[]> res, int[] loc, int row, int n) {        if (row == n) {            //如果行数超过n了,说明所有行上的皇后都满足要求,因此用printBoard方法将得到的一种解决方案加入解集res当中            printBoard(res, loc, n);        } else {            for (int col = 0; col < n; col++) {                //遍历每一行中的每一列                loc[row] = col;                if (isValid(loc, row)) {                    //如果改行中皇后处于的位置是合法的,则深度优先搜索下一行row+1                    dfs(res, loc, row + 1, n);                }            }        }    }        private boolean isValid(int[] loc, int row) {        for (int i = 0; i < row; i++) {            if (loc[row] == loc[i] || Math.abs(loc[row] - loc[i]) == (row - i)) {                //到当前行row之前的所有行,判断是否有某行的皇后与当前行皇后处于同一列,若有,返回false不合法                //到当前行row之前的所有行,判断是否有某行的皇后与当前行皇后处于斜线上(等腰三角形),若有,返回false不合法                return false;            }        }        return true;    }        private void printBoard(ArrayList<String[]> res, int[] loc, int n) {        String[] ans = new String[n];//ans的每个元素表示某一种solution中的某一行        for (int i = 0; i < n; i++) {            String row = new String();            for (int j = 0; j < n; j++) {                if (loc[i] == j)                    row += "Q";                else                    row += ".";            }            ans[i] = row;        }        res.add(ans);    }  }


后记补充:后来才发现这就是NP问题。NP问题的一般解决思路就是递归遍历所有可能性,如果当前可能性合法,则递归继续,如果不合法则返回上一级递归。验证当前可能性是否合法需要一个多项式时间的验证程序。所以是NP问题。

0 0