LeetCode - 解题笔记 - 37 - Sudoku Solver

本文介绍了一种基于深度优先搜索(DFS)的数独求解算法,并提供了C++及Python两种语言的实现方式。该算法通过递归地检查每个空格的有效填数,确保行、列及宫内不重复,最终完成数独填充。

Sudoku Solver

Solution 1

基于前一道题的拓展,本题实际上是dfs的教科书题,和N皇后问题的思路是一致的:在当前配置方案有效的情况下枚举下一种情况。整个枚举过程使用dfs实现,但是判断有效不能直接用上一个题的实现(似乎是因为我的实现申请内存操作过于频繁TLE了),而是采用了[LeetCode] 37. Sudoku Solver 求解数独 - Grandyang - 博客园 (cnblogs.com)这里面的解法,只针对当前位置判定有效就可以了。(原是我的思路不够好/(ㄒoㄒ)/~~)

  • 这个题看起来很复杂,但是由于数独的空位个数是有上限的,所以本题仍然是常数的时间复杂度,同时空间复杂度也是常数级别。
class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        this->dfs(board, 0, 0);
    }
    
private:
    bool dfs(vector<vector<char>>& board, int posX, int posY) {
        // 搜索顺序:行优先
        if (posX >= 9) {
            return true; // 全部枚举完毕,填满可解
        }
        else if (posY >= 9) {
            return this->dfs(board, posX + 1, 0); // 当前行填满,开始向下一行枚举
        }
        else if (board[posX][posY] != '.') {
            return this->dfs(board, posX, posY + 1); // 非空位,跳过
        }
        else {
            // 有效位,开始枚举
            for (char c = '1'; c <= '9'; ++c) {
                
                if (this->isValidSudoku(board, posX, posY, c)) {
                    board[posX][posY] = c;
                    if (this->dfs(board, posX, posY + 1)) {
                        return true;
                    }
                    board[posX][posY] = '.';
                }
            }
        }
        
        return false;
    }
    
    bool isValidSudoku(vector<vector<char>>& board, int posX, int posY, char c) {
        for (int i = 0; i < 9; ++i) {
            if (board[i][posY] == c) {
                return false;
            }
        }
        
        for (int j = 0; j < 9; ++j) {
            if (board[posX][j] == c) {
                return false;
            }
        }
        
        int row = posX - posX % 3, col = posY - posY % 3;
        for (int offsetX = 0; offsetX < 3; ++offsetX) {
            for (int offsetY = 0; offsetY < 3; ++offsetY) {
                if (board[row + offsetX][col + offsetY] == c) {
                    return false;
                }
            }
        }
            
        return true;
    }
};

Solution 2

官方题解解数独 - 解数独 - 力扣(LeetCode) (leetcode-cn.com)使用位状态进一步优化了判定过程(官方题解的前一题使用一个数组保存同行、同列、同块的状态,我的实现是用哈希表),每一个位对应不同的数字(最低位对应0,最高位对应9)是否出现。

Solution 3

Solution 1的python实现

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        self.__dfs(board, 0, 0)
    
    def __dfs(self, board: List[List[str]], posX: int, posY: int) -> bool:
        # print(board[0][2])
        if posX >= 9: return True
        elif posY >= 9: return self.__dfs(board, posX + 1, 0)
        elif board[posX][posY] != '.': return self.__dfs(board, posX, posY + 1)
        else:
            namelist = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
            for c in namelist:
                # print(str(c))
                if self.__isValidSudoku(board, posX, posY, str(c)):
                    # print('K')
                    board[posX][posY] = str(c)
                    if self.__dfs(board, posX, posY + 1): return True
                    board[posX][posY] = '.'
                    
        return False
    
    def __isValidSudoku(self, board: List[List[str]], posX: int, posY: int, c:str) -> bool:
        for i in range(9):
            if board[i][posY] == c: return False
            
        for j in range(9):
            if board[posX][j] == c: return False
            
        row, col = posX - posX % 3, posY - posY % 3
        for offsetX in range(3):
            for offsetY in range(3):
                if board[row + offsetX][col + offsetY] == c: return False
            
        return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值