Leetcode 51.N皇后 回溯求解

本文介绍了解决N皇后问题的算法,使用回溯法和递归,通过检查当前位置是否能放置皇后,并在满足条件时进行插入,最终返回所有不同的棋盘布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

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

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

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

示例 1:

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。

示例 2:

输入:n = 1
输出:[["Q"]]

提示:

  • 1 <= n <= 9

N皇后问题在回溯问题中算是相对比较难的,因为其中的递归调用自有妙招。但是一旦掌握其中的奥妙,求解这类问题将会变得非常简单。返回的类型是双重List,每一个List存储一个棋盘。因此我们可以首先在初始化时将所有元素初始化成 . 。注意题目中所说的每个皇后的移动方式是横向,纵向以及斜向45和135度,根据这个条件我们可以创建出检查函数,传入当前坐标i,j,返回能否在当前位置插入。以下是检查函数代码:

public boolean check(int i,int j,char[][] chs){
        for(int row = 0;row<i;row++){
            if(chs[row][j] == 'Q') return false;
        }
        for(int row=i-1,col=j-1;row>=0&&col>=0;row--,col--){
            if(chs[row][col] == 'Q') return false;
        }
        for(int row=i-1,col=j+1;row>=0 && col<chs.length;row--,col++){
            if(chs[row][col]=='Q') return false;
        }
        return true;
    }

为什么没有检查同一行是否有被占用的情况?这个问题会在下面递归调用中揭晓。

重头戏便是我们的递归调用函数了: 传入参数chs表示当前棋盘,h表示当前横坐标,n表示棋盘大小n。递归方式是通过判断该行的这个元素能否插入元素i,若可以就改为Q插入。然后递归调用下一行。这是因为每一行最多只有一个皇后,因此这一列成功插入后就无需看后面的元素了。这也是为什么不用判断列的原因。

public void backtracking(char[][] chs, int h, int n){
        if(h == n){
            ans.add(new LinkedList<>(tans));
            return;
        }
        for(int i=0;i<n;i++){
            if(check(h,i,chs)){
                chs[h][i] = 'Q';
                tans.add(new String(chs[h]));
                backtracking(chs,h+1,n);
                chs[h][i] = '.';
                tans.remove(tans.size()-1);
            }
        }
    }

以上便是核心代码。整体代码如下:

 

class Solution {
    List<List<String>> ans = new LinkedList<>();
    List<String> tans = new LinkedList<>();
    char[][] chs;
    public List<List<String>> solveNQueens(int n) {
        chs = new char[n][n];
        for(char[] t : chs){
            for(int c=0;c<n;c++){
                t[c] = '.';
            }
        }
        backtracking(chs,0,n);
        
        return ans;
    }
    public void backtracking(char[][] chs, int h, int n){
        if(h == n){
            ans.add(new LinkedList<>(tans));
            return;
        }
        for(int i=0;i<n;i++){
            if(check(h,i,chs)){
                chs[h][i] = 'Q';
                tans.add(new String(chs[h]));
                backtracking(chs,h+1,n);
                chs[h][i] = '.';
                tans.remove(tans.size()-1);
            }
        }
    }
    public boolean check(int i,int j,char[][] chs){
        for(int row = 0;row<i;row++){
            if(chs[row][j] == 'Q') return false;
        }
        for(int row=i-1,col=j-1;row>=0&&col>=0;row--,col--){
            if(chs[row][col] == 'Q') return false;
        }
        for(int row=i-1,col=j+1;row>=0 && col<chs.length;row--,col++){
            if(chs[row][col]=='Q') return false;
        }
        return true;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值