• [Leetcode] N-Queens 系列


    N-Queens 系列题解

    题目来源:

    N-Queens

    N-Queens II


    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.

    board

    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.."]
    ]
    

    Solution

    class Solution {
    private:
        int dimension;
    
        inline bool onDiagonal(int r1, int r2, int c1, int c2) {
            int rowDis = r1 - r2;
            int colDis = c1 - c2;
            return rowDis == colDis || -rowDis == colDis;
        }
    
        bool isValid(const vector<string>& board, int row, int col) {
            if(row == 0)
                return true;
            for (int r = 0; r < row; r++) {
                for (int c = 0; c < dimension; c++) {
                    if (board[r][c] == 'Q' &&
                            (c == col || onDiagonal(r, row, c, col)))
                        return false;
                }
            }
            return true;
        }
    
        void backTrack(vector<vector<string>>& res,
                       vector<string>& board, int row) {
            if (row == dimension) {
                res.push_back(board);
            } else {
                for (int col = 0; col < dimension; col++) {
                    if (isValid(board, row, col)) {
                        board[row][col] = 'Q';
                        backTrack(res, board, row + 1);
                        board[row][col] = '.';
                    }
                }
            }
        }
    public:
        vector<vector<string>> solveNQueens(int n) {
            vector<vector<string>> res;
            if (n == 0)
                return res;
            dimension = n;
            vector<string> board(dimension, string(dimension, '.'));
            backTrack(res, board, 0);
            return res;
        }
    };
    

    解题描述

    这道题就是经典的N皇后问题,要求在给出的n×n的棋盘上放置n个皇后,皇后之前不会互相击杀(不在同一行、同一列、同一对角线上)。上面用到的是递归回溯的办法,每次确定新一行上的皇后,添加新一行的时候要检验与之前行上的皇后是否会相互击杀。

    更优解法

    2018.2.27更新

    评估上面的解法,其实还是存在可以优化的空间。对整个递归回溯解法来说,对特定的维度n来说,递归的层数是固定的,所以时间复杂度主要取决于位置合法性检查,而细想可知,其实上面的解法中合法性检查部分做了很多不必要的操作:遍历棋盘来找到存在皇后的位置。而对整个棋盘而言,我们需要检查的位置其实对每个维度来说是固定的:

    1. n个列
    2. 2n - 1条左对角线
    3. 2n - 1条右对角线

    权衡利弊,我们可以采用以空间换时间的办法,记录上述5n -2个位置上的皇后占据情况来降低检查的时间复杂度。下面给出具体实现:

    class Solution {
    private:
        int dimension;
        vector<bool> colFlags, leftDiaFlags, rightDiaFlags;
    
        void backTrack(vector<vector<string>>& res,
                       vector<string>& board, int row) {
            if (row == dimension) {
                res.push_back(board);
                return;
            }
            for (int col = 0; col < dimension; col++) {
                if (!colFlags[col] &&
                        !leftDiaFlags[dimension - 1 + row - col] &&
                        !rightDiaFlags[row + col]) {
                    colFlags[col]
                            = leftDiaFlags[dimension - 1 + row - col]
                            = rightDiaFlags[row + col]
                            = true;
                    board[row][col] = 'Q';
                    backTrack(res, board, row + 1);
                    board[row][col] = '.';
                    colFlags[col]
                            = leftDiaFlags[dimension - 1 + row - col]
                            = rightDiaFlags[row + col]
                            = false;
                }
            }
        }
    public:
        vector<vector<string>> solveNQueens(int n) {
            vector<vector<string>> res;
            if (n == 0)
                return res;
            dimension = n;
            vector<string> board(dimension, string(dimension, '.'));
            // 三种位置上的皇后是否存在的标记:
            colFlags.resize(dimension, false); // 1. 列
            leftDiaFlags.resize(2 * dimension - 1, false); // 2. 左对角线
            rightDiaFlags.resize(2 * dimension - 1, false); // 3. 右对角线
            backTrack(res, board, 0);
            return res;
        }
    };
    

    N-Queens II

    这道题题意只要求求出N皇后解法数目,不要求给出具体解法,则与第一版差别不大,只需略作修改。

    Solution

    class Solution {
    private:
        int dimension;
        vector<bool> colFlags, leftDiaFlags, rightDiaFlags;
    
        void backTrack(int& res, int row) {
            if (row == dimension) {
                ++res;
                return;
            }
            for (int col = 0; col < dimension; col++) {
                if (!colFlags[col] &&
                    !leftDiaFlags[dimension - 1 + row - col] &&
                    !rightDiaFlags[row + col]) {
                    colFlags[col]
                            = leftDiaFlags[dimension - 1 + row - col]
                            = rightDiaFlags[row + col]
                            = true;
                    backTrack(res, row + 1);
                    colFlags[col]
                            = leftDiaFlags[dimension - 1 + row - col]
                            = rightDiaFlags[row + col]
                            = false;
                }
            }
        }
    public:
        int totalNQueens(int n) {
            int res = 0;
            if (n == 0)
                return res;
            dimension = n;
            // 三种位置上的皇后是否存在的标记:
            colFlags.resize(dimension, false); // 1. 列
            leftDiaFlags.resize(2 * dimension - 1, false); // 2. 左对角线
            rightDiaFlags.resize(2 * dimension - 1, false); // 3. 右对角线
            backTrack(res, 0);
            return res;
        }
    };
    
  • 相关阅读:
    Maven学习
    Android屏幕适配
    Java多线程中的死锁问题[转]
    数据结构基本概念和算法分析
    AsyncTask(异步任务)
    Android自定义滑动开关按钮
    记录一些我记不住的技术
    2017携程Web前端实习生招聘笔试题总结
    JavaScript ES5面向对象实现一个todolist
    原生JavaScript实现一个简单的todo-list
  • 原文地址:https://www.cnblogs.com/yanhewu/p/8476743.html
Copyright © 2020-2023  润新知