LeetCode:37(解数独):在二维数组中的逐步回溯:一般思维+进阶思维
发布日期:2021-05-07 14:08:12 浏览次数:20 分类:精选文章

本文共 2298 字,大约阅读时间需要 7 分钟。

数独是一种经典的逻辑谜题,需要通过填充空白格,确保每一行、每一列以及每个3x3的小宫格都包含数字1到9且不重复。解决数独问题需要遵循严格的规则,并通过有效的算法来逐步填充空格。

数独的规则

  • 行规则:每一行不能包含重复的数字。
  • 列规则:每一列也不能包含重复的数字。
  • 宫格规则:每个3x3的小宫格也不能包含重复的数字。
  • 解决思路

    使用回溯算法结合剪枝策略来解决数独问题。回溯算法通过递归的方式,逐步填充每个空格,并检查是否违反规则,如果违反则回溯,尝试下一个可能性。

    具体步骤如下:

  • 初始化预处理:记录每一行、每一列和每个宫格中已存在的数字。
  • 递归填充:从左上角开始,尝试填充每个空格,依次测试数字1到9。
  • 检查冲突:对于每个候选数字,检查是否存在于当前行、列或宫格中。
  • 递归回溯:如果数字冲突,回溯到上一个位置,尝试下一个数字。
  • 优化策略:优先处理可能性较少的空格,减少搜索空间。
  • 代码实现

    以下是基于Java的数独解决方案:

    class Solution {
    boolean[][] rows = new boolean[9][10]; // 行中已存在的数字
    boolean[][] cols = new boolean[9][10]; // 列中已存在的数字
    boolean[][][][] grid = new boolean[3][3][10]; // 3x3宫格中已存在的数字
    public void solveSudoku(char[][] board) {
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    if (board[i][j] != '.') {
    int num = board[i][j] - '0';
    rows[i][num] = cols[j][num] = grid[i / 3][j / 3][num] = true;
    }
    }
    }
    if (dfs(board, 0, 0)) {
    return;
    }
    // 如果无解(理论上题目保证有解)
    for (int i = 0; i < 9; i++) {
    for (int j = 0; j < 9; j++) {
    board[i][j] = (rows[i][j] ? (grid[i / 3][j / 3][j] ? (cols[j][j] ? (j + 1) : 0) : 0) : '.');
    }
    }
    }
    private boolean dfs(char[][] board, int row, int col) {
    if (row == 9) {
    return true;
    }
    if (col == 9) {
    return dfs(board, row, 0);
    }
    if (board[row][col] != '.') {
    return dfs(board, row, col + 1);
    }
    for (int num = 1; num <= 9; num++) {
    if (!rows[row][num] && !cols[col][num] && !grid[row / 3][col / 3][num]) {
    rows[row][num] = cols[col][num] = grid[row / 3][col / 3][num] = true;
    board[row][col] = (char) ('0' + num);
    if (dfs(board, row, col + 1)) {
    return true;
    }
    rows[row][num] = cols[col][num] = grid[row / 3][col / 3][num] = false;
    board[row][col] = '.';
    }
    }
    return false;
    }
    }

    代码解释

  • 初始化预处理:遍历数独网格,记录每一行、每一列和每个宫格中已存在的数字。
  • 递归函数dfs:负责填充空格,使用深度优先搜索策略,逐步填充每个空格,检查是否违反规则。
  • 剪枝策略:在递归过程中,若发现当前行、列或宫格已经没有空位,提前返回,避免不必要的计算。
  • 回溯机制:在填充一个数字后,递归处理下一个位置;如果递归返回,清空当前位置,尝试下一个数字。
  • 这种方法确保了每一步填充都是有效的,能够最终解决数独问题。

    上一篇:LeetCode301:回溯中的枚举
    下一篇:Java并发:网友对ThreadLocal的理解误区和知识重点!

    发表评论

    最新留言

    路过,博主的博客真漂亮。。
    [***.116.15.85]2025年03月29日 15时20分34秒