【JS每日一算法】45. N 皇后(递归回溯)

272 阅读3分钟

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

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

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

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

 

示例:

queens.jpg

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

更多JS版本题解点击链接关注该仓库👀

/**
 * @description: 递归回溯    TC:O(2^n)  SC:O(n)
 * @author: JunLiangWang
 * @param {*} n   给定矩阵大小
 * @return {*}
 */
function recursionBacktracking(n){
    /**
     * 该方案利用递归回溯的方式,通过递归逐行遍历矩阵元素,然后在递归中逐列遍历当前行
     * 的元素,找到与已找到的点(points)不同行/不同列/不同对角线的点,并将该点加入到
     * 已找到的点(points)中,从下一行继续递归,直到递归完矩阵所有行,证明已找到所有符
     * 合条件的点。
     * 
     * 判断当前点是否与已找到的点
     * 不同行(由于是逐行递归的,因此当前行的点肯定与已找到的点不同行,此处无需判断)
     * 不同列(即:已找到的点的列不等于当前点的列)
     * 不同对角线(即:已找到的点的列与行之和/差不等于当前点的列与行之和/差)
     */

    // 定义输出数组
    let outArray=[];

    /**
     * @description: 递归回溯
     * @author: JunLiangWang
     * @param {*} currentRow  当前行
     * @param {*} points      已选中的点
     * @return {*}
     */    
    function recursion(currentRow,points){
        // 如果当前行超出了矩阵大小,证明已找到所有符合条件的点
        if(currentRow===n)
        {
            // 将已找到的点(points),构造为符合答案的输出(例如:"..Q.")
            // 添加到输出数组中(outArray)
            let out=[]
            for(let item of points)
            {
                let temp=new Array(n).fill('.');
                temp[item.col]='Q';
                out.push(temp.join(''));
            }
            outArray.push(out)
            return ;
        }
        // 如果当前行(currentRow)未超出矩阵大小,则逐列遍历当前行的元素,找到与
        // 已找到的点(points)不同行/不同列/不同对角线的点,并将该点加入到已找到
        // 的点(points)中,从下一行继续递归
        
        // 逐列遍历当前行(currentRow)的元素
        for(let col=0;col<n;col++)
        {
            // 遍历已找到的点,判断当前点是否与已找到的点
            // 不同行(由于是逐行递归的,因此当前行的点肯定与已找到的点不同行,此处无需判断)
            // 不同列(即:已找到的点的列不等于当前点的列)
            // 不同对角线(即:已找到的点的列与行之和/差不等于当前点的列与行之和/差)
            let index=0;
            while(index<points.length&&points[index].col!=col
                &&currentRow+col!=points[index].row+points[index].col&&
                currentRow-col!=points[index].row-points[index].col)index++;
            // 如果index不等于points数组长度,证明已找到的点中有与当前点同行/同列/同对
            // 角线的情况,否则,则没有该情况,将该点加入到已找到的点(points)中,从下一
            // 行继续递归
            if(index===points[index].length)
            {
                //将该点加入到已找到的点(points)中,从下一行继续递归
                recursion(currentRow+1,[...points,{
                    row:currentRow,
                    col:col
                }]);
            }
        }
    }
    // 调用递归
    recursion(0,[]);
    // 返回结果
    return outArray;
}

来源:力扣(LeetCode)