力扣记录:回溯算法5棋盘问题——51 N皇后,37 解数独

本次题目

  • 51 N皇后
  • 37 解数独

51 N皇后

  • 回溯:约束条件:皇后不能同行,不能同列,不能同斜线。
    1. 定义全局二维数组存放最终结果,定义层数row记录当前放置第几层(第几个皇后),定义二维棋盘,传入n,棋盘和层数;
    2. 放置到最后一层时终止;
    3. 每一行循环每个位置,如果当前位置合法则放置(直接在二维棋盘上修改)然后进入下一层递归,随后回溯。
  • 注意:
    1. 判断当前位置是否合法,与已放置的皇后不能同行,不能同列,不能同斜线(因为只放置了当前行之前的行,因此只需要检查之前的行,不用检查后面的行。斜线有左上和右上)。
    2. 定义全为“.”的二维数组分别对其中每一行fill()。将二维数组转为List遍历每行,字符数组转为字符串String.copyValueOf()。
class Solution {
    //定义全局二维数组存放最终结果
    List<List<String>> result = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        //定义层数row记录当前放置第几层(第几个皇后)
        int row = 0;
        //定义二维棋盘,传入n,棋盘和层数
        char[][] chessboard = new char[n][n];
        //初始化
        for(char[] c : chessboard){
            Arrays.fill(c, '.');
        }
        //开始回溯
        backtracking(n, chessboard, row);
        //返回结果
        return result;
    }
    //回溯函数
    private void backtracking(int n, char[][] chessboard, int row){
        //放置到最后一层时终止
        if(row == n){
            //将二维数组转为List
            result.add(Array2List(chessboard));
            return;
        }
        //每一行循环每个位置
        for(int i = 0; i < n; i++){
            //如果当前位置合法则放置(直接在二维棋盘上修改)然后进入下一层递归,随后回溯
            if(isValue(chessboard, row, i)){
                chessboard[row][i] = 'Q';
                backtracking(n, chessboard, row + 1);
                chessboard[row][i] = '.';
            }
        }
    }
    //判断当前位置是否合法,与已放置的皇后不能同行,不能同列,不能同斜线
    private boolean isValue(char[][] chessboard, int row, int col){
        //因为只放置了当前行之前的行,因此只需要检查之前的行,不用检查后面的行
        //不能同列
        for(int i = 0; i < row; i++){
            if(chessboard[i][col] == 'Q') return false;
        }
        //不能同斜线
        //左上
        for(int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--){
            if(chessboard[i][j] == 'Q') return false;
        }
        //右上
        for(int i = row - 1, j = col + 1; i >=0 && j < chessboard.length; i--, j++){
            if(chessboard[i][j] == 'Q') return false;
        }
        return true;
    }
    //将二维数组转为List遍历每行
    private List<String> Array2List(char[][] arr){
        List<String> list = new ArrayList<>();
        for(char[] c : arr){
            list.add(String.copyValueOf(c));
        }
        return list;
    }
}

37 解数独

  • 回溯:二维递归,答案唯一。
    1. 输入9x9数组返回布尔值判断是否符合条件;
    2. 当遍历完九宫格时终止(可不用);
    3. 判断当前输入是否合法,同行不能重复,同列不能重复,小九宫格不能重复。
class Solution {
    public void solveSudoku(char[][] board) {
        //开始回溯
        backtracking(board);
    }
    //回溯函数
    private boolean backtracking(char[][] board){
        //当遍历完九宫格时终止(可不用)
        for(int i = 0; i < 9; i++){// 遍历行
            for(int j = 0; j < 9; j++){//遍历列
                //已有数字跳过
                if(board[i][j] != '.') continue;
                //遍历插入1-9,若满足条件则递归回溯,否则下一个
                for(char c = '1'; c <= '9'; c++){
                    if(isVaild(board, c, i, j)){
                        board[i][j] = c;
                        //若下一个满足条件,继续返回
                        if(backtracking(board)) return true;
                        board[i][j] = '.';
                    }
                }
                //若1-9都不满足,返回false
                return false;
            }
        }
        //九宫格遍历完后找到解,返回true
        return true;
    }
    //判断当前输入是否合法,同行不能重复,同列不能重复,小九宫格不能重复
    private boolean isVaild(char[][] board, char c, int row, int col){
        //同行不能重复
        for(int i = 0; i < 9; i++){
            if(board[i][col] == c) return false;
        }
        //同列不能重复
        for(int j = 0; j < 9; j++){
            if(board[row][j] == c) return false;
        }
        //小九宫格不能重复
        //获取当前行列所在小九宫格的起始行列位置
        int row_small = (row / 3) * 3;
        int col_small = (col / 3) * 3;
        for(int i = row_small; i < row_small + 3; i++){
            for(int j = col_small; j < col_small + 3; j++){
                if(board[i][j] == c) return false;
            }
        }
        //最后满足条件
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
力扣是一个在线编程平台,提供了大量的算法题目,可以帮助程序员提高算法能力。回溯算法是一种搜索算法,它通过不断地尝试所有可能的来求问题。在回溯算法中,我们首先定义一个空间,然后从空间中搜索所有可能的,直到找到符合要求的为止。回溯算法通常用于求组合问题、排列问题、子集问题等。 在 Java 中实现回溯算法,通常需要定义一个递归函数来搜索空间。在递归函数中,我们首先判断当前状态是否符合要求,如果符合要求,则将当前状态加入到集中;否则,我们继续搜索下一个状态。在搜索下一个状态时,我们需要对当前状态进行一些修改,然后递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。 以下是回溯算法的一般步骤: 1. 定义空间:确定问题空间,并定义一个数据结构来表示空间中的每个状态。 2. 确定约束条件:确定哪些状态是合法的,并定义一个函数来判断当前状态是否符合要求。 3. 确定搜索策略:确定搜索空间的顺序,并定义一个函数来生成下一个状态。 4. 搜索空间:使用递归函数搜索空间,如果当前状态符合要求,则将其加入到集中;否则,继续搜索下一个状态。 5. 回溯:当搜索完所有可能的状态后,回溯到上一个状态,继续搜索其他可能的状态。 以下是一个力扣题目的回溯算法 Java 实现示例: ``` class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); public List<List<Integer>> subsets(int[] nums) { dfs(nums, 0); return res; } private void dfs(int[] nums, int start) { res.add(new ArrayList<>(path)); for (int i = start; i < nums.length; i++) { path.add(nums[i]); dfs(nums, i + 1); path.remove(path.size() - 1); } } } ``` 该算法用于求给定数组的所有子集。在递归函数中,我们首先将当前状态加入到集中,然后从当前位置开始搜索下一个状态。在搜索下一个状态时,我们将当前元素加入到路径中,并递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值