回溯算法part06 算法

回溯算法part06 算法

今日任务:
● 51. N皇后
● 37. 解数独

1.leetcode 51. N皇后

https://leetcode.cn/problems/n-queens/description/

class Solution {
    //存储结果
    List<List<String>> result=new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        //存放一个棋盘,一个棋盘是一个二维数组
        char[][] chessboard=new char[n][n];
        //将棋盘填满逗点
        for(char[] c:chessboard){
            Arrays.fill(c,'.');
        }
        backrtacing(chessboard,n,0);//棋盘,多深,当前行(深度)
        return result;
        //n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,
        //并且使皇后彼此之间不能相互攻击。
        //皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子
    }
    public void backrtacing(char[][] chessboard,int n,int row){
        //确定终止条件,如果此时深度已经为n了
        if(row==n){
            //将棋盘(二维数组)加进结果(二维集合)中
            //将棋盘二维数组转成一维集合
            //调用函数
            result.add(Array2List(chessboard));
            return;
        }
        //进行判断棋盘二维数组的每一个一维(控制横向)
        for(int i=0;i<n;i++){
            //第一行第一个元素表示是c[row][i]//row控制整体深度,第几行//i控制横向,哪一个元素
            //要放皇后前,先检查这个位置的元素合不合法
            if(isValid(row,i,n,chessboard)){
                //合法了我们就放
                chessboard[row][i]='Q';
                //接着看接下来一层的一维,因为前一个一维已经处理好放不放n皇后了
                backrtacing(chessboard,n,row+1);
                //进行回溯
                chessboard[row][i]='.';//前面函数调用完已经处理加不加进去了
                //然后进行下一次
            }
        }
    }
    //将二维数组转成一维集合
    public List Array2List(char[][] chessboard){
        List<String> list=new ArrayList<>();
        for(char[] c:chessboard){
            list.add(String.copyValueOf(c));
        }
        return list;
    }
    //判断是不是有效的棋盘位置
     public boolean isValid(int row, int col, int n, char[][] chessboard) {
        // 检查列
        for (int i=0; i<row; ++i) { // 相当于剪枝
            if (chessboard[i][col] == 'Q') {
                return false;
            }
        }

        // 检查45度对角线
        for (int i=row-1, j=col-1; i>=0 && j>=0; i--, j--) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }

        // 检查135度对角线
        for (int i=row-1, j=col+1; i>=0 && j<=n-1; i--, j++) {
            if (chessboard[i][j] == 'Q') {
                return false;
            }
        }
        return true;
    }
}

2.leetcode 37. 解数独

https://leetcode.cn/problems/sudoku-solver/description/

class Solution {
    public void solveSudoku(char[][] board) {
        //没有返回值
        backtracing(board);
    }
    public boolean backtracing(char[][] board){
        //遍历数独的一维横行(遍历行)
        for(int i=0;i<board.length;i++){
            //遍历列
            for(int j=0;j<board.length;j++){
                //如果遇到是数字的元素位置就跳过
                if(board[i][j]!='.'){
                    continue;
                }
                //遇到不是数字元素的位置,也就是遇到逗点了,需要填充数字
                for(char k='1';k<='9';k++){
                    //判断该位置是不是合法的,合法才可以加入数字
                    if(isValidSudoku(i,j,k,board)){
                        board[i][j]=k;
                        //开始递归
                        if(backtracing(board)){//如果有合适的直接返回
                            return true;
                        }
                        //进行回溯
                        board[i][j]='.';
                    }
                }
                //9个数字都试完了还不行,直接返回false
                return false;
            }
        }
        //遍历完没有返回false,说明找到了合适棋盘位置了
        return true;
    }
    //判断棋盘是否合法
    private boolean isValidSudoku(int row, int col, char val, char[][] board){
        // 同行是否重复
        for (int i = 0; i < 9; i++){
            if (board[row][i] == val){
                return false;
            }
        }
        // 同列是否重复
        for (int j = 0; j < 9; j++){
            if (board[j][col] == val){
                return false;
            }
        }
        // 9宫格里是否重复
        int startRow = (row / 3) * 3;
        int startCol = (col / 3) * 3;
        for (int i = startRow; i < startRow + 3; i++){
            for (int j = startCol; j < startCol + 3; j++){
                if (board[i][j] == val){
                    return false;
                }
            }
        }
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值