LeetCode第 51 题:N皇后 (C++)

51. N皇后 - 力扣(LeetCode)
LeetCode第 51 题:N皇后 (C++)_第1张图片

回溯法,经典问题,网上解析太多了。
回溯算法详解 - N皇后 - 力扣(LeetCode)这篇讲解蛮好的,代码也够清晰。
利用vector进行维护,vec[0] = 1 :代表第0行的元素放在第一列。

关于对角线的判断:
常规方法

bool isOk(int row, int col, vector &vec){
	int left = col - 1, right = col + 1;
	for (int i = row - 1; i >= 0; --i){ //逐行往上考察每一行
		if (vec[i] == col) return false;  //第i行的col列有棋子吗
		if (left >= 0){  //检查左上对角线:第i行left列(col前面一列)有棋子吗
			if (vec[i] == left) return false;
		}
		if (right >= 0){  //检查右上对角线:第i行left列(col前面一列)有棋子吗
			if (vec[i] == right) return false;
		}
		--left; ++right;
	}
	return true;
}

精简方法:绝对值判断(当初书上好像有讲过)

bool isOk(int row, int col, vector &vec){
	for (int i = row - 1; i >= 0; --i){ //逐行往上考察每一行
		if (vec[i] == col) return false; //第i行的col列有棋子吗
		if (abs(row - i) == abs(col - vec[i])) return false; //对角线检查
	}
	return true;
}

因为题目要求返回的是一个vector>,所以函数设计的参数尽量使用引用,避免大量拷贝。

class Solution {
public:
    vector> res;
    vector flags;//标志位,flags[i] = j,代表第i行的皇后位于第j列
    vector tmp;
    int n;
    void dfs(int row){
        if(row == n){//放置结束,存储
            for(int i = 0; i < n; ++i){
                string s;
                for(int j = 0; j < n; ++j){
                    if(flags[i] == j)   s += "Q";
                    else s += ".";
                }
                tmp[i] = s;
            }
            res.push_back(tmp);
        }

        for(int j = 0; j < n; ++j){
            if(isOk(row, j)){
                flags[row] = j;//第row行的棋子放在第j列
                dfs(row+1);
            }
        }
    }

    bool isOk(int row, int col){
        for(int i = row - 1; i >= 0; --i){ //逐行往上考察每一行
            if(flags[i] == col)   return false;//该列已放置过
            if(abs(row - i) == abs(col - flags[i]))   return false;//对角线已放置,行的差值=列的差值
        }
        return true;
    }

    vector> solveNQueens(int n) {
        flags.resize(n);
        tmp.resize(n);
        this->n = n;
        dfs(0);
        return res;
    }
};

你可能感兴趣的:(leetcode,leetcode,算法,回溯问题)