[Leetcode]N-Queens

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值