N-Queens I/II

需求I:

n皇后问题,有一个n*n的棋盘,有n个皇后,要保证每个皇后不能在同一行、同一列、同一对角线,这样才不会出现冲突,求解n皇后共有多少种放置方式。

分析:

1、创建n*n的char型二维数组,初始化为'.',表示没有放置皇后。

2、因为皇后不能在同一行,所以将皇后i放到行i,逐行确定每个皇后的位置。假设,现在要确定皇后num(num的范围是0~n-1)的位置,如果num==n,那么说明已经找到了一个可行解,将该数组转化成字符串集合,添加到结果集合中即可。如果num<n,那么该皇后可以放置的位置有[0, n-1],假设放到位置i处,判断[num][i]处放置皇后是否合法,如果合法,将[num][i]置为'Q',然后寻找皇后num+1的位置,然后将[num][i]置为'.',继续判断皇后num是否可以放到其它位置。如果不合法,那么继续判断皇后是否可以放到其它位置。

3、判断皇后的位置是否合法。因为每个皇后都位于不同行,所以只需要判断皇后的位置是否位于同一列或者同一对角线即可。对于皇后num,只需要判断比num小的皇后的位置即可。假如两个皇后的位置分别是[i1][j1]和[i2][j2],那么只需要保证j1 != j2(不在同一列),并且|i1-i2| != |j1-j2|(不在同一对角线)即可。

4、将二维字符数组转成字符串集合。创建字符串集合,将二维数组的每一行转成字符串,添加到集合中即可。

代码:

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new LinkedList<List<String>>();
        
        //创建n*n数组,初始化为'.'
        char[][] board = new char[n][n];
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                board[i][j] = '.';
        
        //求皇后0的位置
        dfs(0, board, res);
        return res;
    }
    
    //确定皇后num的位置
    public void dfs(int num, char[][] board, List<List<String>> res){
        //如果num==board.length,说明已经找到了可行解,将其添加到res中
        if(num == board.length){
            res.add(arraytolist(board));
            return;
        }
        
        //确定皇后num放置的位置
        for(int i = 0; i < board.length; i++){
            if(valid(num, i, board)){
                board[num][i] = 'Q';
                dfs(num+1, board, res);
                board[num][i] = '.';
            }
        }
    }
    
    //判断皇后num的位置是否合法
    public boolean valid(int num, int col, char[][] board){
        for(int i = 0; i < num; i++){
            for(int j = 0; j < board.length; j++){
                if(board[i][j] == 'Q'){
                    if(j == col || Math.abs(i-num) == Math.abs(j-col))
                        return false;
                }
            }
        }
        
        return true;
    }
    
    //将二维字符数组转化成字符串集合
    public List<String> arraytolist(char[][] board){
        List<String> res = new LinkedList<String>();
        
        for(int i = 0; i < board.length; i++)
            res.add(new String(board[i]));
        
        return res;
    }
}

需求II:

n皇后问题,求总的排列个数。

分析:

相对于上述问题,不需要将所有可行解存储起来,只需要记录个数即可,思路相同,更简单一些。

代码:

class Solution {
    //相对于NQueens I来说,不需要创建集合来存储结果,只需要一个变量,来递增数量即可
    int res = 0;
    public int totalNQueens(int n) {
        //创建n*n二维字符数组,初始化为'.'
        char[][] board = new char[n][n];
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                board[i][j] = '.';
        
        dfs(0, board);//确定皇后0的位置
        return res;
    }
    
    public void dfs(int num, char[][] board){
        if(num == board.length)
        {
            res++;//已经找到了一个可行解
            return;
        }
        
        for(int i = 0; i < board.length; i++){
            if(valid(num, i, board)){
                board[num][i] = 'Q';
                dfs(num+1, board);
                board[num][i] = '.';
            }
        }
    }
    
    public boolean valid(int num, int col, char[][] board){
        for(int i = 0; i < num; i++){
            for(int j = 0; j < board.length; j++){
                if(board[i][j] == 'Q'){
                    if(j == col || Math.abs(i-num) == Math.abs(j-col))
                        return false;
                }
            }
        }
        
        return true;
    }
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值