LeetCode 51. N-Queens

本文介绍了一种解决N皇后问题的有效方法,通过递归和回溯策略找出所有可能的棋盘配置,使得N个皇后互不攻击。提供了两种C++实现方案及一种Java版本,并详细解释了核心算法思想。

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

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

img

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.

Example:

Input: 4
Output: [
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above.

解题思路:

在一行中的每一个位置 试探 是否可以放皇后,通过判断 对角线与列值是否有符合条件, 符合的话进入下一行位置判断(使用递归),如果此行放置皇后的位置不符合条件那么 回溯刚刚位置为’.,当row的值为n是意味着已经找到一组N—queens的组合 输出即可。整体就是DFS + 回溯的思想

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<string> t(n, string(n, '.'));
        vector<vector<string>> v;
        solve(v, t, 0);
        return v;
    }
    // row 表示行 对行进行递归
    void solve(vector<vector<string>> &v, vector<string> &t, int row){
        if(row == t.size()){
            v.push_back(t);
            return;
        }
        for(int col = 0; col < t.size(); col++){
            //尝试此位置可否放置皇后
            t[row][col] = 'Q';
            if(IsValid(t, row, col)) solve(v, t, row + 1);
            //不满足条件回溯
            t[row][col] = '.';
        }
    }
    bool IsValid(vector<string> &t, int row, int col){
        bool valid = true;
        for(int i = 0; i < row && valid; valid = t[i++][col] != 'Q');
        for(int i = row, j = col; valid && i-- && j--; valid = t[i][j] != 'Q');
		for(int i = row, j = col; valid && i-- && ++j < t.size(); valid = t[i][j] != 'Q');
        return valid;
    }
};

优化版本:

还是同样的思想,改进两个点

  1. 通过一个queens 数组来保存每行中Q的列的位置,例如图中的solution1 queens = {1, 3, 0, 2}, 行对应的列的位置,也就是说queens数组中没有重复的值 表示符合条件。
  2. 判断对角线的位置时,有一个规律;如果两点的行的差的绝对值等于列的差的绝对值那么他们 在同一对角线上 这样可以简化对角先的 判断

C++ version:

class Solution{
    public:
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> v;
        vector<int> queens(n);
        solve(v, queens, 0);
        return v;
    }
    void solve(vector<vector<string>> &v, vector<int> &queens, int row){
        int n = queens.size();
       //满足条件时,给v赋值
        if(row == n){
            vector<string> t(n, string(n, '.'));
            for(int i = 0; i < n; i++){
                t[i][queens[i]] = 'Q';
            }
            v.push_back(t);
            return;
        }
      //试探当前行的每个位置
        for(int col = 0; col < n; col++){
            queens[row] = col;
            if(isValid(queens, row)) solve(v, queens, row + 1);
        }
    }
    bool isValid(vector<int> &queens, int row){
        for(int i = 0; i < row; i++){
           // 如果列上不符合条件 或者 对角线上
            if(queens[row] == queens[i] || abs(queens[row] - queens[i]) == abs(i - row)){
                return false;
            }
        }
        return true;
    }
};

java version:

class Solution {
    public List<List<String>> solveNQueens(int n) {
    	List<List<String>> ans = new ArrayList<>();
    	if(n <= 0) return ans;
    	solve(ans,new int[n], 0);
    	return ans;
    }
    public void solve(List<List<String>>res, int[] queens, int row) {
    	int n = queens.length;
    	if(row == n) {
    		List<String> t = new ArrayList<>();
    		for(int i = 0; i < n; i++) {
    			String st = "";
    			for(int j = 0; j < n; j++) {
    				if(queens[i] == j) st += 'Q';
    				else st += '.';
    			}
    			t.add(st);
    		}
    		res.add(t);
     		return;
    	}
    	for(int col = 0; col < n; col++) {
    		queens[row] = col;
    		if(IsValid(queens, row)) {
    			solve(res, queens, row + 1);
    		}
    	}
    }
    public boolean IsValid(int [] queens , int row) {
    	for(int i = 0; i < row; i++) {
    		if(queens[row] == queens[i] || Math.abs(queens[i] - queens[row]) == Math.abs(i - row)) {
    			return false;
    		}
    	}
    	return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值