题解 | #N皇后问题#

N皇后问题

https://www.nowcoder.com/practice/c76408782512486d91eea181107293b6

回溯的基本框架:

// 怎么做?
function Nqueen(n) {
    let res = 0;
    
    const backtrack = function (?) {
        // 终止条件是啥
        if (?) {
            res++;
            return;
        }
        // 怎么遍历
        for (?) {
            // 做什么操作?
            ?

            backtrack(board, row + 1);

            // 取消操作
            ?
        }
    };

    backtrack(?);

    return res;
}

module.exports = {
    Nqueen,
};

解题步骤:

  • 问1:思考N皇后问题怎么做?它是在做什么?

答:在 N * N 的棋盘上放置棋子 Q ,Q有个特性就是它会攻击所在行所在列以及斜对角上的棋子。现在要求你在棋盘上放上最多的Q,问你有几种放法。

所以,你需要一个 N * N 的 棋盘 board,记录你的放法。

  • 问2:你会怎么放?

答:第一行先放一个Q,下一行遍历所有的格子,在一个合适的格子上放上Q,然后再到下一行。直到棋盘的最后一行放上了Q,就完成了一种方法。

所以,backtrack的入参是:

const backtrack = function(board, row) {}

终止条件:

if(row === board.length) {
  res++;
  return;
}

每行遍历所有列,在合适的格子上放上Q:

for(let c = 0; c < board[row].length; c++) {
  // 判断当前格子是否合适放置,不合适就不放了
  if(!isvalid(board, row, col)) continue;
  // 做的操作 
  board[row][c] = 'Q';
  
  backtrack(board, row + 1);
  
  // 取消操作
  board[row][c] = '#';
}
  • 问3:怎么判断格子是否合适:

答:当前列有Q不能再放;当前格子左上角有Q不能再放(不只是左上角的一个格子,是整个左上角斜对角线);当前格子右上角有Q不能再放。

伪代码如下:

function isValid(board, row, col) {
  for(let i = 0; i < board.length; i++) {
   if(board[i][col] === 'Q') return false;
  }
  
  for(i = row - 1, j = col - 1; i && j >= 0 ; i--, j--)  {
   if(board[i][j]==='Q') return false;
  }
  
  for(i = row-1, j = col + 1; i && j < bCols; i--,j++) {
   if(board[i][j] === 'Q') return false;
  }
  
  return ture;
}

最终结果:

function Nqueen(n) {
    const board = Array.from(Array(n), () => Array(n).fill("#"));

    let res = 0;

    const backtrack = function (board, row) {
        // 终止条件是啥
        if (row === board.length) {
            res++;
            return;
        }
        // 怎么遍历
        for (let c = 0; c < board[0].length; c++) {
            if (!isValid(board, row, c)) continue;
            // 做什么操作?
            board[row][c] = "Q";

            backtrack(board, row + 1);

            // 取消操作
            board[row][c] = "#";
        }
    };

    backtrack(board, 0);

    return res;
}

function isValid(board, row, col) {
    const n = board.length;

    // 同一列有Q不行
    for (let i = 0; i < n; i++) {
        if (board[i][col] === "Q") {
            return false;
        }
    }

    // 左上角有Q不行
    for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
        if (board[i][j] === "Q") {
            return false;
        }
    }

    // 右上角有Q不行
    for(let i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
        if(board[i][j] === 'Q') {
            return false;
        }
    }

    return true;
}

module.exports = {
    Nqueen,
};

全部评论

相关推荐

joe2333:怀念以前大家拿华为当保底的日子
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务