前端刷题:回溯算法 | 刷题打卡

92 阅读2分钟

一、题目描述:

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 示例1:
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
示例2:
输入:n = 1
输出:[["Q"]]
提示: 1 <= n <= 9
皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。

二、思路分析:

N皇后问题是一道经典的回溯算法题目。回溯算法是一个类似枚举的搜索尝试过程,在搜索尝试过程中寻找问题的解。当发现不满足求解条件的时候就回溯返回,尝试别的路径。做题的模版如下:

  1. 首先写好跳出条件,符合条件的时候才放入返回结果中
  2. 已经算过的数进行标记,不再计算
  3. 往下遍历,结束后返回上一步。 伪码如下:
let res = [];
const DFS = ()=>{
    if(满足结束条件){
        res.push(路径)
        return;
    }
    for(遍历选择列表){
        去掉已经选择过的数;
        选择
        DFS(路径,选择列表)
        回退选择
    }
}

三、AC 代码:

N皇后的问题最重要的是选择条件的判断,要判断当前元素前面所有行里的当前列,左右对角线方向是否已经放置过,然后再遍历循环。

var solveNQueens = (n)=> {
    let grid = new Array(n).fill(null).map(e=>new Array(n).fill('.'));
    let res = [];
    const hasQueen = (grid,i,j)=>{
        for(let k=0;k<i;k++){
            for(let m=0;m<n;m++){
                if(grid[k][m]=='Q'&&(m==j||k+m==i+j||k-m==i-j)){
                    return false;
                }
            }
        }
        return true;
    }
    const DFS = (grid,i)=>{
        if(i==n){
            res.push(grid.slice().map(e=>e.join('')))
            return;
        }
        for(let j=0;j<n;j++){
            if(hasQueen(grid,i,j)){
                grid[i][j] = 'Q';
                DFS(grid,i+1,j);
                grid[i][j] = '.'
            }
        }
    }
    DFS(grid,0)
    return res;
};

四、总结:

回溯算法的场景非常的多,基本思想类似于图的深度优先搜索,二叉树的后序遍历,所以,有时候我们感觉就是深度优先遍历。 当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。

参考文档: