天天看点

leetcode华为面试算法题-51. N 皇后

作者:程序员的交流电

#头条创作挑战赛#

leetcode华为面试算法题-51. N 皇后
leetcode华为面试算法题-51. N 皇后

N皇后问题一直是大厂面试的常见算法问题,也是在学习回溯算法时的一个经典案例问题。这里和全排列问题差不多,都是不断的选择然后撤销选择,当满足结束条件,记录选择的路径。本文主要写的就是回溯算法对N皇后问题的解决

本质上回溯算法是一个暴力算法,复杂度都比较高。不像动态规划存在“重叠子问题”,然后通过DP数组或者存储状态的手段,来进行“剪枝”操作,提高执行效率。回溯算法一般用于求解可以穷举的,结果是有多少种的这类问题;动态规划常用于求解最值的问题。

class Solution {

    List<List<String>> res = new ArrayList<>();

    /* 输入棋盘的边长n,返回所有合法的放置 */
    public List<List<String>> solveNQueens(int n) {
        // "." 表示空,"Q"表示皇后,初始化棋盘
        char[][] board = new char[n][n];
        for (char[] c : board) {
            Arrays.fill(c, '.');
        }
        backtrack(board, 0);
        return res;
    }

    public void backtrack(char[][] board, int row) {
        // 每一行都成功放置了皇后,记录结果
        if (row == board.length) {
            res.add(charToList(board));  
            return;
        }

        int n = board[row].length;
        // 在当前行的每一列都可能放置皇后
        for (int col = 0; col < n; col++) {
            // 排除可以相互攻击的格子
            if (!isValid(board, row, col)) {
                continue;
            }
            // 做选择
            board[row][col] = 'Q';
            // 进入下一行放皇后
            backtrack(board, row + 1);
            // 撤销选择
            board[row][col] = '.';
        }
    }

    /* 判断是否可以在 board[row][col] 放置皇后 */
    public boolean isValid(char[][] board, int row, int col) {
        int n = board.length;
        // 检查列是否有皇后冲突
        for (int i = 0; i < n; i++) {
            if (board[i][col] == 'Q') {
                return false;
            }
        }

        // 检查右上方是否有皇后冲突
        for (int i = row - 1, j = col + 1; i >=0 && j < n; i--, j++) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }

        // 检查左上方是否有皇后冲突
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }

    public List charToList(char[][] board) {
        List<String> list = new ArrayList<>();
        for (char[] c : board) {
            list.add(String.copyValueOf(c));
        }
        return list;
    }
}
           

本题是回溯算法的一个经典题目。本质上就是暴力穷举的问题。

需要注意的是判断当前皇后位置是否会被攻击。如果使用的是二维数组来记录的话,需要注意,正方向的斜着,行号加列号相等的在同一斜线,反方向斜着,行号减列号相等的在同一斜线,这个是判断当前位置是否合法的一个比较简单的方法。