【LeetCode】N-Queens N皇后 - Medium

n皇后问题是将n个皇后放置在n*n的棋盘上,皇后彼此之间不能相互攻击。
给定一个整数n,返回所有不同的n皇后问题的解决方案。
每个解决方案包含一个明确的n皇后放置布局,其中”Q”和”.”分别表示一个女王和一个空位置。

样例
对于4皇后问题存在两种解决的方案:
[
[“.Q..”, // Solution 1
“…Q”,
“Q…”,
“..Q.”],
[“..Q.”, // Solution 2
“Q…”,
“…Q”,
“.Q..”]
]

挑战
你能否不使用递归完成?

标签
递归 深度优先搜索

相关题目
中等 Pacific Atlantic Water Flow27 %
中等 组合33 %
中等 N皇后问题 II41 %

(1)C++

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;
const int N = 4;// N皇后

class NQueens{
public:
    vector<vector<string>> solveNQueens(int n){
        vector<vector<string>> result;
        vector<vector<int>> mark;// 标记皇后的攻击位置(标记数组)
        vector<string> location;//存储某个摆放皇后的结果,当完成一次递归找到后,将其放入result
        for(int i = 0; i < n; i++){// 初始化标记数组
            mark.push_back(vector<int>());
            for(int j = 0; j < n; j++){
                mark[i].push_back(0);
            }
            location.push_back("");// C++中的字符串处理
            location[i].append(n, '.');// 初始化location:每一行(字符串)都追加n个'.'(表示空位,后续若放置了皇后将变成'Q')
        }
        helper(0, n, location, result, mark);
        return result;
    }

private:
    // 第x行y列放置皇后(置1),mark为一个棋盘
    void put_down_the_queen(int x, int y,
                            vector<vector<int>>& mark){
        static const int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1};// 方向数组
        static const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};// (x,y)对应看
        int directions = sizeof(dx) / sizeof(int);  // directions = 8;
        mark[x][y] = 1;
        for(int i = 1; i < mark.size(); i++){
            for(int j = 0; j < directions; j++){// 共8个方向(四面八方),每个方向 向外延伸1至N-1
                int new_x = x + i * dx[j];//dx[]、dy[]表方向; i表延伸长度。
                int new_y = y + i * dy[j];// x、y表当前位置
                if(new_x >= 0 && new_x < mark.size() &&
                   new_y >= 0 && new_y < mark.size()){
                    mark[new_x][new_y] = 1;// 将延伸方向上的所有坐标置1.(被标记处不可以再放置皇后Q)
                }
            }
        }
    }

    void helper(int row, int nRows,// nRows:N皇后,共nRows行。 row:代表完成了row个皇后的放置,正在放置第row行皇后
                  vector<string> &location,
                  vector<vector<string>>& result,
                  vector<vector<int>>& mark){
        if(row == nRows){// 说明一次递归完成,找到一个可行解
            result.push_back(location);
            return;
        }
        for(int j = 0; j < nRows; j++){// 按列优先的顺序尝试(在每一行row的遍历中)
            if(mark[row][j] == 0){// 若当前位置尚未被标记,即可能是皇后Q的合法位置
                vector<vector<int>> tmpMark = mark;//记录回溯前mark的镜像

                location[row][j] = 'Q';//放置皇后
                put_down_the_queen(row, j, mark);// 放置皇后, 并更新mark标记数组

                helper(row + 1, nRows, location, result, mark);// 递归下一行皇后位置
                mark = tmpMark;//回溯后要怎么做? ——①将mark重新赋值为回溯前的状态
                location[row][j] = '.';// ②将当前尝试的皇后位置重新置空('.')
            }
        }
    }
};

int main()
{
    vector<vector<string>> result;
    NQueens nQueens;
    result = nQueens.solveNQueens(N);
    for(int i = 0; i < result.size(); i++){
        cout << "i = " << i << endl;
        for(int j = 0; j < result[i].size(); j++){
            cout << result[i][j].c_str() << endl;
        }
        cout << endl;
    }
    return 0;
}

(2)Java

package Recursion;

import java.util.ArrayList;
import java.util.List;

public class N_Queens {
    /**
     * Get all distinct N-Queen solutions
     * @param n: The number of queens
     * @return: All distinct solutions
     * For example, A string '...Q' shows a queen on forth position
     */
    public List<List<String>> solveNQueens(int n){
        List<List<String>> results = new ArrayList<>();
        if(n <= 0){
            return results;
        }

        search(results, new ArrayList<>(), n);
        return results;
    }

    /**
     * results store all of the chessboards
     * ❤️ mark store the column indices for each row
     * ❤️ mark中存储的是每一行中有且仅有的唯一一个皇后Q的下标!!!
     *
     * @param mark 按列优先的顺序搜索,并记录每行Q的列下标
     * @param nRows 总行数
     */
    private void search(List<List<String>> results,
                        List<Integer> mark,
                        int nRows){
        if(mark.size() == nRows){
            results.add(drawChessboard(mark));
            return;
        }
        for (int colIndex = 0; colIndex < nRows; colIndex++) {
            if (!isValid(mark, colIndex)) {
                continue;
            }
            mark.add(colIndex);
            search(results, mark, nRows);
            mark.remove(mark.size() - 1); //mark.remove( mark.indexOf(colIndex) );
        }

    }

    private List<String> drawChessboard(List<Integer> mark){
        List<String> chessboard = new ArrayList<>();
        for(int i = 0; i < mark.size(); i++){
            StringBuilder sb = new StringBuilder();
            for(int j = 0; j < mark.size(); j++){
                sb.append(j == mark.get(i)? 'Q' : '.');
            }
            chessboard.add(sb.toString());
        }
        return chessboard;
    }

    /**
     *
     * @param mark
     * @param colIndex 当前遍历的列。
     * ❤️ mark.get(rowIndex):表示第rowIndex行的皇后Q的列下标
     * @return
     */
    private boolean isValid(List<Integer> mark, int colIndex){
        int nRows = mark.size();
        for(int rowIndex = 0; rowIndex < mark.size(); rowIndex++){
            if(mark.get(rowIndex) == colIndex){
                // mark中rowIndex行的Q位置(列下标)与当前遍历的colIndex相同
                return false;
            }
            if(rowIndex + mark.get(rowIndex) == nRows + colIndex){
                //❤️ 当前行的皇后Q的坐标x + y之和与其【副对角线】的坐标和相同
                // 排除当前行的皇后Q的【副对角线】上的点
                return false;
            }
            if (rowIndex - mark.get(rowIndex) == nRows - colIndex) {
                //❤️ 当前行的皇后Q的坐标y - x之差与其【主对角线】的坐标差相同
                // 排除当前行的皇后Q的【主对角线】上的点
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args){
        N_Queens n_queens = new N_Queens();
        List<List<String>> results = new ArrayList<>();
        results = n_queens.solveNQueens(4);
        for(int i = 0; i < results.size(); i++){
            System.out.println("i = " + i);
            System.out.println(results.get(i).toString().replace(',','\n') + "\n");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/ljyljyok/article/details/79472168