算法奇妙屋(三十)-递归、回溯与剪枝的综合问题 3

文章目录

一. 力扣 51. N 皇后

1. 题目解析

题目的主要要求是皇后不能处在同行同列以及对角线上, 同时输出结果是二维数组, 每一行的元素需要包含方案的所有坐标

2. 算法原理

决策树

原理

3. 代码

java 复制代码
class Solution {
    List<List<String>> ret;
    List<String> path;
    boolean[] col;
    boolean[] dig1;
    boolean[] dig2;
    public List<List<String>> solveNQueens(int n) {
        ret = new ArrayList<>();
        path = new ArrayList<>();
        col = new boolean[n];
        dig1 = new boolean[2 * n];
        dig2 = new boolean[2 * n];
        dfs(n, 0);
        return ret;
    }
    void dfs(int n, int r) {
        if (r == n) {
            ret.add(new ArrayList(path));
            return;
        }
        // i代表列, 即纵坐标, r为横坐标
        for (int i = 0; i < n; i++) {
            // 剪枝掉不满足的情况
            if (!col[i] && !dig1[r - i + n] && !dig2[r + i]) {
                col[i] = dig1[r - i + n] = dig2[r + i] = true;
                // 将结果添加到path中
                StringBuilder tmp = new StringBuilder();
                for (int j = 0; j < n; j++) {
                    if (j == i) {
                        tmp.append("Q");
                    }else {
                        tmp.append(".");
                    }
                }
                path.add(tmp.toString());
                // 向下一层遍历
                dfs(n, r + 1);
                // 回溯
                path.remove(path.size() - 1);
                col[i] = dig1[r - i + n] = dig2[r + i] = false;
            }
        }
    }
}

二. 力扣 526. 优美的排列

1. 题目解析

2. 算法原理

3. 代码

java 复制代码
class Solution {
    int ret = 0;
    boolean[] check;
    public int countArrangement(int n) {
        check = new boolean[n + 1];
        dfs(n, 1);
        return ret;
    }
    void dfs(int n, int pos) {
        if (pos == n + 1) {
            ret++;
            return;
        }
        for (int i = 1; i <= n; i++) {
            if (!check[i] && (i % pos == 0 || pos % i == 0)) {
                check[i] = true;
                dfs(n, pos + 1);
                // 回溯
                check[i] = false;
            }
        }
    }
}

三. 力扣 36. 有效的数独

1. 题目解析

这里和N皇后有点类似, 但不同的是对角线可以相同

2. 算法原理

3. 代码

java 复制代码
class Solution {
    public boolean isValidSudoku(char[][] board) {
        boolean[][] row = new boolean[9][10];
        boolean[][] col = new boolean[9][10];
        boolean[][][] grid = new boolean[3][3][10];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') {
                    continue;
                }
                int k = board[i][j] - '0';
                if (board[i][j] >= '1' && board[i][j] <= '9' && !row[i][k] && !col[j][k] && !grid[i / 3][j / 3][k]) {
                    row[i][k] = true;
                    col[j][k] = true;
                    grid[i / 3][j / 3][k] = true;
                }else {
                    return false;
                }
            }
        }
        return true;
    }
}

四. 力扣 37. 解数独

1. 题目解析

与上道题基本一致, 但这里是填写数字

2. 算法原理

与N皇后十分类似, 但是因为我们可能存在填错的情况, 因此每次递归都要两层循环来遍历二维数组, 同时要有第三层循环来试1-9这九个数字, dfs是有返回值的, 重点中的重点是理解什么时候返回false, 什么时候返回true

3. 代码

java 复制代码
class Solution {
    boolean[][] row = new boolean[9][10];
    boolean[][] col = new boolean[9][10];
    boolean[][][] grid = new boolean[3][3][10];

    public void solveSudoku(char[][] board) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] != '.') {
                    int k = board[i][j] - '0';
                    row[i][k] = true;
                    col[j][k] = true;
                    grid[i / 3][j / 3][k] = true;
                }

            }
        }
        dfs(board);
    }
    boolean dfs(char[][] board) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (board[i][j] == '.') {
                    for (int k = 1; k <= 9; k++) {
                        if (!row[i][k] && !col[j][k] && !grid[i / 3][j / 3][k]) {
                            row[i][k] = true;
                            col[j][k] = true;
                            grid[i / 3][j / 3][k] = true;
                            board[i][j] = (char)(k + 48);
                            // 这里我们做判断, 当前情况正确时, 我们直接返回给上一层, 也有保留填写好board的作用
                            if (dfs(board)) {
                                return true;
                            }
                            // 当前情况不满足, 继续试其他数字, 恢复现场
                            row[i][k] = false;
                            col[j][k] = false;
                            grid[i / 3][j / 3][k] = false;
                            board[i][j] = '.';
                        }
                    }
                    // 有空格但没有填写数字, 说明情况不成立, 再次剪枝, 不用继续枚举错误情况
                    return false;
                }
            }
        }
        // 全部填满
        return true;
    }
}
相关推荐
大明者省6 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
白狐_7987 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2588 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记8 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
杨航 AI8 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
船厂电气自动化ai大模型9 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光9 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
叠层归一研究院10 小时前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi
zlinear数据采集卡11 小时前
D223的PWM电机控制:6路独立脉冲+加减速算法深度解析
arm开发·stm32·嵌入式硬件·算法·fpga开发·架构
杨石兴11 小时前
31、玩具MoM:用2x2矩阵串起全套流程
人工智能·算法·矩阵·电磁学