📜  算法测验| Sudo放置:设置1 |问题5(1)

📅  最后修改于: 2023-12-03 15:11:33.357000             🧑  作者: Mango

算法测验 | Sudo放置:设置1 | 问题5

本次算法测验即将开始!本次测试的主题为 Sudo 放置。这是熟悉的游戏,我们将会测试你的算法设计和实现能力。本次测试总共有 5 个问题,每个问题都有不同的难度级别。答题时间为 40 分钟,祝你好运!

题目描述

在一个 $n \times n$ 的矩阵中填充数独问题的数字,使得每一行、每一列和每一 个 $3 \times 3$ 的子矩阵中的数字都是 $1$ 到 $9$ 的数字,且不同的个数为 $9$。

编写一个程序,以二维数组表示的 Sudo 棋盘作为输入,输出一个已经填充好数字的 Sudo 棋盘。如果无法找到可行的解决方案,则返回一个空的 Sudo 棋盘。

注意:您可以假设矩阵的尺寸为 $n\times n$,其中$n$是一个平方数。

输入格式

二维数组表示的 Sudo 棋盘,其中 $0$ 表示空格。

示例:
[
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,3,0,0,0,0,0,0,0],
    [0,0,0,0,7,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0]
]
输出格式

输出一个已经填充好数字的 Sudo 棋盘,如果无法找到可行的解决方案,则返回一个空的 Sudo 棋盘。

示例:
[
    [5,6,7,8,1,4,3,9,2],
    [1,9,8,6,5,2,4,7,3],
    [4,3,2,9,8,7,5,6,1],
    [8,1,5,3,7,6,2,4,9],
    [3,7,9,1,2,8,6,5,4],
    [2,4,6,5,9,0,7,3,8],
    [6,8,1,4,3,5,9,2,7],
    [7,2,3,0,6,9,8,1,5],
    [9,5,4,2,0,1,0,0,6]
]
题目分析

本题可以采用 DFS 深度优先遍历 + 回溯搜索的方式求解。

首先我们需要对给定的矩阵进行预处理,找出所有尚未填充数字的位置。这样我们就可以依次对这些位置进行搜索。

对于每个未填充数字的位置,我们需要判断在这个位置上可以填充哪些数字。这里可以使用一个辅助函数来完成。

在搜索过程中,需要满足 Sudo 规则,即每一行、每一列和每一个 $3\times 3$ 的子矩阵中的数字都是 $1$ 到 $9$ 的数字,且不同的个数为 $9$。

代码实现
def fillSudoku(board):
    """
    :type board: List[List[int]]
    :rtype: List[List[int]]
    """
    n = len(board)
    empty_cells = []

    for i in range(n):
        for j in range(n):
            if board[i][j] == 0:
                empty_cells.append((i, j))

    def check_row(i, num):
        for j in range(n):
            if board[i][j] == num:
                return False
        return True

    def check_col(j, num):
        for i in range(n):
            if board[i][j] == num:
                return False
        return True

    def check_block(i, j, num):
        bi, bj = i // 3 * 3, j // 3 * 3
        for k in range(3):
            for l in range(3):
                if board[bi + k][bj + l] == num:
                    return False
        return True

    def backtrack(index):
        if index == len(empty_cells):
            return True

        i, j = empty_cells[index]

        for num in range(1, 10):
            if (check_row(i, num)
                and check_col(j, num)
                and check_block(i, j, num)):
                board[i][j] = num
                
                if backtrack(index + 1):
                    return True
                
                board[i][j] = 0

        return False

    backtrack(0)
    return board
总结

本题经典的搜索算法题目,需要对矩阵中各个未填充位置进行判断,判断此时可以填充哪些数字,再根据 Sudo 规则进行搜索剪枝。相对其他算法难度较小,是典型的算法考察题目之一。