回溯算法之棋盘问题hard

12.18 51N皇后

题目:

回溯算法之棋盘问题hard_第1张图片

思路:

(1)用回溯的思想寻找每一行皇后的位置

(2)皇后位置的约束,创建一个新函数。使得与之前行的皇后不在同一列或斜线

(3)45度斜线行列和相等;135度斜线行列差相等。

时间复杂度(n!)

class Solution {
    List> res=new ArrayList<>();
    LinkedList path=new LinkedList<>();
    int n;
    public List> solveNQueens(int n) {
        this.n=n;
        traceback(0);
        return res;
    }
    public void traceback(int start){
        if(start==n){
            res.add(new LinkedList<>(path));
            return;
        }
        for(int i=0;i=0&&col+(row-i)=0&&col-(row-i)> res = new ArrayList<>();
    boolean[] usedCol, usedDiag45, usedDiag135;    // boolean数组中的每个元素代表一条直(斜)线
    public List> solveNQueens(int n) {
        usedCol = new boolean[n];                  // 列方向的直线条数为 n
        usedDiag45 = new boolean[2 * n - 1];       // 45°方向的斜线条数为 2 * n - 1
        usedDiag135 = new boolean[2 * n - 1];      // 135°方向的斜线条数为 2 * n - 1
        //用于收集结果, 元素的index表示棋盘的row,元素的value代表棋盘的column
        int[] board = new int[n];
        backTracking(board, n, 0);
        return res;
    }
    private void backTracking(int[] board, int n, int row) {
        if (row == n) {
            //收集结果
            List temp = new ArrayList<>();
            for (int i : board) {
                char[] str = new char[n];
                Arrays.fill(str, '.');
                str[i] = 'Q';
                temp.add(new String(str));
            }
            res.add(temp);
            return;
        }

        for (int col = 0; col < n; col++) {
            if (usedCol[col] | usedDiag45[row + col] | usedDiag135[row - col + n - 1]) {
                continue;
            }
            board[row] = col;
            // 标记该列出现过
            usedCol[col] = true;
            // 同一45°斜线上元素的row + col为定值, 且各不相同
            usedDiag45[row + col] = true;
            // 同一135°斜线上元素row - col为定值, 且各不相同
            // row - col 值有正有负, 加 n - 1 是为了对齐零点
            usedDiag135[row - col + n - 1] = true;
            // 递归
            backTracking(board, n, row + 1);
            usedCol[col] = false;
            usedDiag45[row + col] = false;
            usedDiag135[row - col + n - 1] = false;
        }
    }
}

12.18 37解数独

回溯算法之棋盘问题hard_第2张图片

思路:

(1)如何回溯。卡哥说是二维递归,比之前做的所有回溯题都要多一维。要在每一行每一列选择1到9中的一个数,而例如n皇后只用在每一行选择一个位置。

【代码上好像是多了两维,是从一层for循环变成了三层。但实际上这种维度的变化相当于只是多了两个参数而已。而二维与一维的最大不同点就是不能用递归的一个参数来表示行列变化了,这样每次都要递归都要走一遍已经确定数字的格子,不过递归过的格子数有标记,也就还是从下一个格子开始了。】

(2)判断有效性。根据空格的行列和填入的数判断是否有效。

(3)难点:回溯函数中什么时候返回false,什么时候返回true。

class Solution {
    public void solveSudoku(char[][] board) {
        traceback(board);
    }
    public boolean traceback(char[][] board){
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j]!='.')continue;
                //!注意k是char,数字带引号
                for(char k='1';k<='9';k++){
                    if(isvaild(board,k,i,j)){
                        board[i][j]=k;
                        if(traceback(board))return true;
                        board[i][j]='.';
                    }
                }
                return false;
                //说明当前方案下,ij空格填入任何数都无法满足方案
            }
        }
        return true;
    }
    public boolean isvaild(char[][] board,char k,int row,int col){
        //同行
        for(int j=0;j<9;j++){
            if(board[row][j]==k)return false;
        }
        //同列
        for(int i=0;i<9;i++){
            if(board[i][col]==k)return false;
        }
        //同九宫格
        int startRow=row/3*3;
        int startCol=col/3*3;
        for(int i=startRow;i

你可能感兴趣的:(数据结构与算法,数据结构,算法,java,leetcode)