java解数独(力扣Leetcode37)

数独问题

力扣原题链接

问题描述

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

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

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

示例

示例:

输入:board = [[“5”,“3”,“.”,“.”,“7”,“.”,“.”,“.”,“.”],[“6”,“.”,“.”,“1”,“9”,“5”,“.”,“.”,“.”],[“.”,“9”,“8”,“.”,“.”,“.”,“.”,“6”,“.”],[“8”,“.”,“.”,“.”,“6”,“.”,“.”,“.”,“3”],[“4”,“.”,“.”,“8”,“.”,“3”,“.”,“.”,“1”],[“7”,“.”,“.”,“.”,“2”,“.”,“.”,“.”,“6”],[“.”,“6”,“.”,“.”,“.”,“.”,“2”,“8”,“.”],[“.”,“.”,“.”,“4”,“1”,“9”,“.”,“.”,“5”],[“.”,“.”,“.”,“.”,“8”,“.”,“.”,“7”,“9”]]

输出:

[["5","3","4","6","7","8","9","1","2"],
 ["6","7","2","1","9","5","3","4","8"],
 ["1","9","8","3","4","2","5","6","7"],
 ["8","5","9","7","6","1","4","2","3"],
 ["4","2","6","8","5","3","7","9","1"],
 ["7","1","3","9","2","4","8","5","6"],
 ["9","6","1","5","3","7","2","8","4"],
 ["2","8","7","4","1","9","6","3","5"],
 ["3","4","5","2","8","6","1","7","9"]]

解题思路

我们可以使用回溯算法来解决数独问题。

  1. 遍历数独中的每一个格子,如果格子为空白,就尝试填入数字 1-9,然后检查填入后是否合法。
  2. 若填入的数字合法,则继续递归地填充下一个格子。
  3. 若填入的数字不合法,则回溯到上一个状态,尝试其他的数字。
  4. 当遍历到最后一个格子时,如果所有的格子都已经被填满且合法,则找到了一个解决方案。

复杂度分析

  • 时间复杂度:回溯算法的时间复杂度取决于数独的解的数量。对于 9x9 的数独,一般情况下有多个解,因此时间复杂度是指数级别的。
  • 空间复杂度:O(1),除了结果列表之外,主要消耗的是递归调用栈的空间。

好的,下面是这个代码的算法步骤演示:

算法步骤演示

  1. 初始化

    • 创建一个函数 solveSudoku,该函数接受一个二维字符数组 board 作为参数。
    • solveSudoku 函数中调用 backtrack 函数,并将 board 作为参数传递给它。
  2. 回溯函数

    • 回溯函数 backtrack 接受一个二维字符数组 board 作为参数,它用于填充数独的空白格子。
    • 遍历数独的每一个格子:
      • 如果当前格子为空白 '.',则尝试填入数字 '1''9'
      • 对于每一个尝试填入的数字,检查该数字是否合法(满足数独规则):
        • 检查当前行是否包含目标字符。
        • 检查当前列是否包含目标字符。
        • 检查当前 3x3 宫是否包含目标字符。
      • 如果该数字合法,则将其填入当前格子,并递归调用 backtrack 函数,尝试填充下一个格子。
      • 如果递归调用返回 true,表示找到了一个解决方案,直接返回 true
      • 如果递归调用返回 false,表示当前尝试不成功,回溯到上一个状态,继续尝试其他的数字。
    • 如果遍历完所有的格子都成功填充,说明找到了一个解决方案,返回 true
    • 如果没有找到解决方案,返回 false
  3. 检查数字合法性的函数

    • 检查数字合法性的函数 isvalid 接受一个二维字符数组 board、要填入的数字 c、以及目标格子的行坐标 row 和列坐标 col 作为参数。
    • 首先根据目标格子的位置计算出当前 3x3 宫的左上角的行坐标和列坐标。
    • 然后分别检查当前行、当前列以及当前 3x3 宫是否包含目标数字 c
    • 如果不包含目标数字,则返回 true,否则返回 false

请添加图片描述

算法实现

class Solution {
    // 解决数独问题的入口方法
    public void solveSudoku(char[][] board) {
        backtrack(board);
    }

    // 回溯函数,用于填充数独格子
    boolean backtrack(char[][] board) {
        // 遍历数独格子
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board.length; j++) {
                // 如果当前格子为空白
                if (board[i][j] == '.') {
                    // 尝试填入数字 '1' 到 '9'
                    for (char k = '1'; k <= '9'; k++) {
                        // 如果当前填入的数字符合数独规则
                        if (isvalid(board, k, i, j)) {
                            // 填入数字并递归调用回溯函数
                            board[i][j] = k;
                            if (backtrack(board)) return true;
                            // 如果递归调用返回 false,说明填入当前数字不行,回溯到上一步
                            board[i][j] = '.';
                        }
                    }
                    // 如果尝试了所有数字都不行,返回 false
                    return false;
                }
            }
        }
        // 如果所有格子都已填满,返回 true
        return true;
    }

    // 检查当前填入的数字是否符合数独规则
    boolean isvalid(char[][] board, char c, int row, int col) {
        // 计算当前格子所在的 3x3 宫的左上角的行坐标和列坐标
        int startRow = row - row % 3;
        int startCol = col - col % 3;

        // 检查当前行是否包含目标字符
        for (int i = 0; i < board.length; i++) {
            if (board[row][i] == c) return false;
        }

        // 检查当前列是否包含目标字符
        for (int i = 0; i < board.length; i++) {
            if (board[i][col] == c) return false;
        }

        // 检查当前 3x3 宫是否包含目标字符
        for (int i = startRow; i < startRow + 3; i++) {
            for (int j = startCol; j < startCol + 3; j++) {
                if (board[i][j] == c) return false;
            }
        }

        // 如果所有检查都通过,返回 true
        return true;
    }
}

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BenChuat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值