LeetCode题练习与总结:解数独

一、题目

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

二、解题思路

  1. 选择一个空格:在数独板上找一个还没有填数字的空格。
  2. 尝试填入数字:尝试在该空格中填入1到9之间的数字。
  3. 检查有效性:检查填入的数字是否满足数独的规则。这包括检查当前行、列和3x3的子宫格。
  4. 递归解决:如果填入的数字有效,递归地尝试解决剩余的空格。
  5. 回溯:如果在递归过程中发现当前填入的数字导致无法继续填入其他空格,回溯到上一个空格,尝试填入另一个数字。

三、具体代码

class Solution {
    public void solveSudoku(char[][] board) {
        if (board == null || board.length != 9 || board[0].length != 9) {
            return;
        }

        solve(board, 0, 0); // 从第一个空格开始递归解决
    }

    private boolean solve(char[][] board, int row, int col) {
        if (row == 9) { // 如果到达最后一行,意味着所有空格都已尝试,返回成功
            return true;
        }

        if (col == 9) { // 移动到下一行
            return solve(board, row + 1, 0);
        }

        if (board[row][col] != '.') { // 如果当前格有数字,移动到下一列
            return solve(board, row, col + 1);
        }

        // 尝试填入1到9之间的数字
        for (char num = '1'; num <= '9'; num++) {
            if (isValid(board, row, col, num)) {
                board[row][col] = num; // 填入数字
                if (solve(board, row, col + 1)) { // 递归解决下一个空格
                    return true;
                }
                board[row][col] = '.'; // 回溯,移除数字
            }
        }
        return false; // 如果没有数字可以填入,返回失败
    }

    private boolean isValid(char[][] board, int row, int col, char num) {
        // 检查行
        for (int i = 0; i < 9; i++) {
            if (board[row][i] == num) {
                return false;
            }
        }

        // 检查列
        for (int i = 0; i < 9; i++) {
            if (board[i][col] == num) {
                return false;
            }
        }

        // 检查3x3子宫格
        int startRow = row - row % 3;
        int startCol = col - col % 3;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[startRow + i][startCol + j] == num) {
                    return false;
                }
            }
        }

        return true; // 如果数字不违反规则,返回true
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 时间复杂度主要取决于尝试填充数字的次数以及每次尝试时的验证过程。
  • 尝试次数:最坏情况下,每个空格都尝试填入1到9之间的所有数字,因此尝试次数大约是 9^9(因为9x9的数独有81个空格,每个空格最多尝试9次)。
  • 验证过程:每次尝试填入数字时,都需要验证该数字是否有效,这包括检查当前行、列和3x3的宫。最坏情况下,每个验证过程需要检查9个元素,因此对于每次尝试,验证过程的时间复杂度是 O(9)
  • 综上所述,最坏情况下的时间复杂度是 O(9^9 * 9),即 O(9^10)
  • 这是一个非常巨大的数字,但在实际情况中,由于数独的规则限制,通常不需要尝试所有可能的数字组合。
2. 空间复杂度
  • 空间复杂度主要取决于递归调用栈的深度。
  • 递归调用栈:在最坏情况下,每次递归调用都可能需要进入一个新的递归层级,直到找到一个合适的数字或者填满所有空格。由于数独最多有81个空格,递归调用栈的最大深度为81。
  • 因此,空间复杂度是 O(递归调用栈深度),即 O(81)O(1),因为这里的常数可以忽略不计。

五、总结知识点

  1. 回溯算法:这是一种通过递归来实现的深度优先搜索策略。它尝试在给定的问题空间中搜索解决方案,并且在搜索过程中,如果遇到不可行的路径,会返回到上一步,尝试其他可能的选项。

  2. 递归solve 方法是一个递归函数,它尝试填入数字并递归地调用自身来解决剩余的空格。递归的基本情况是当所有空格都被填满时,这时会返回 true,表示找到了一个解决方案。

  3. 参数传递solve 方法通过 boardrowcol 三个参数来跟踪当前的数独板状态和下一个需要填充的空格位置。

  4. 边界检查:在 solve 方法的开始,有对 rowcol 的边界检查,确保它们不会超出数独板的范围。

  5. 条件判断:代码中有多个条件判断,用于确定当前位置是否可以填入某个数字。这包括检查当前行、列和3x3的宫格内是否已经存在该数字。

  6. 有效性验证isValid 方法用于验证尝试填入的数字是否符合数独的规则。它检查了三个维度:行、列和3x3的宫格。

  7. 回溯:当尝试填入的数字导致冲突时,通过将当前位置的值重置为 '.'(表示空格),算法会回溯到上一步,尝试其他可能的数字。

  8. 字符操作:代码中使用了字符型变量 num 来表示数字1到9,这是为了与数独板上的字符表示保持一致。

  9. 数学计算:在计算3x3宫格的起始行和列时,使用了取模运算 % 来确定当前位置所在的宫格。

  10. 空格处理:代码中对数独板上的空格('.')进行了特殊处理,只有当当前位置是空格时,才会尝试填入数字。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

相关推荐

  1. LeetCode练习总结解数

    2024-03-17 10:00:03       20 阅读
  2. LeetCode练习总结:组合总和

    2024-03-17 10:00:03       20 阅读
  3. LeetCode练习总结:组合-77

    2024-03-17 10:00:03       11 阅读
  4. LeetCode练习总结:最长有效括号

    2024-03-17 10:00:03       23 阅读
  5. LeetCode练习总结:搜索旋转排序数组

    2024-03-17 10:00:03       17 阅读
  6. LeetCode练习总结:字母异位词分组

    2024-03-17 10:00:03       28 阅读
  7. LeetCode练习总结:排列序列--60

    2024-03-17 10:00:03       18 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 10:00:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 10:00:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 10:00:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 10:00:03       20 阅读

热门阅读

  1. Axios 中的文件上传(Upload File)方法

    2024-03-17 10:00:03       20 阅读
  2. linux系统kubernetes的yaml文件

    2024-03-17 10:00:03       21 阅读
  3. CMake官方教程9--打包文件

    2024-03-17 10:00:03       19 阅读
  4. JWT令牌

    JWT令牌

    2024-03-17 10:00:03      21 阅读
  5. React懒加载

    2024-03-17 10:00:03       22 阅读
  6. awk命令——文本数据格式处理工具

    2024-03-17 10:00:03       24 阅读
  7. 门牌制作-蓝桥杯?-Lua 中文代码解题第3题

    2024-03-17 10:00:03       23 阅读
  8. 飞桨科学计算套件PaddleScience

    2024-03-17 10:00:03       19 阅读
  9. Redis列表:高效消息通信与实时数据处理的利器

    2024-03-17 10:00:03       21 阅读