LeetCode:37. 解数独

58 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

37. 解数独

来源:力扣(LeetCode)

链接: leetcode.cn/problems/su…

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

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

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

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

示例 1: 在这里插入图片描述

输入: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"]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:

在这里插入图片描述

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字或者 '.'
  • 题目数据 保证 输入数独仅有一个解

解法

  • DFS回溯+集合剪枝:首先获取哪些位置需要补数字,且该位置能补的数字有多少,之后进行循环遍历,如果填完数之后继续下一个。

代码实现

DFS

python实现

class Solution:
    def solveSudoku(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        rows = [set(range(1, 10)) for _ in range(9)]
        cols = [set(range(1, 10)) for _ in range(9)]
        block = [set(range(1, 10)) for _ in range(9)]

        empty = []

        for i in range(9):
            for j in range(9):
                if board[i][j] != '.':
                    val = int(board[i][j])
                    rows[i].remove(val)
                    cols[j].remove(val)
                    block[i//3*3+j//3].remove(val)
                else:
                    empty.append((i, j))
        

        def backtrace(iters=0):
            if iters == len(empty):
                return True
            
            i, j = empty[iters]
            index = i // 3 * 3 + j // 3
            for val in rows[i] & cols[j] & block[index]:
                rows[i].remove(val)
                cols[j].remove(val)
                block[index].remove(val)
                board[i][j] = str(val)
                if backtrace(iters+1):
                    return True
                rows[i].add(val)
                cols[j].add(val)
                block[index].add(val)
            return False
        
        backtrace()

c++实现

#include <iostream>
#include <algorithm>
using namespace std;

class Solution {
public:
    bool backTrack(int iters, vector<vector<int>> &empty, vector<vector<char>> & board, vector<set <int>> &rows, vector<set <int>> &cols, vector<set<int>> &block) {
        if (iters == empty.size()) return true;
        int i = empty[iters][0];
        int j = empty[iters][1];
        int index = i / 3 * 3 + j / 3;
        set<int> inner_sections;
        for (auto val: rows[i]) inner_sections.insert(val);
        for (auto val: cols[j]) inner_sections.insert(val);
        for (auto val: block[index]) inner_sections.insert(val);
        for (auto val: inner_sections) {
            rows[i].erase(val);
            cols[j].erase(val);
            block[index].erase(val);
            board[i][j] = char(val);
            if (backTrack(iters+1, empty, board, rows, cols, block)) return true;
            rows[i].insert(val);
            cols[j].insert(val);
            block[index].insert(val);
        }
        return false;

    }

    void solveSudoku(vector<vector<char>>& board) {
        vector<set<int>> rows(9, {1, 2, 3, 4, 5, 6, 7, 8, 9});
        vector<set<int>> cols(9, {1, 2, 3, 4, 5, 6, 7, 8, 9});
        vector<set<int>> block(9, {1, 2, 3, 4, 5, 6, 7, 8, 9});
        vector<vector<int>> empty;
        for (int i=0; i<9; i++) {
            for (int j=0; j<9; j++) {
                if (board[i][j] != '.') {
                    int val = int(board[i][j]);
                    rows[i].erase(val);
                    cols[j].erase(val);
                    block[i/3*3+j/3].erase(val);
                }
                else
                    empty.push_back({i, j});
            }
        }

        backTrack(0, empty, board, rows, cols, block);
    }
};

复杂度分析

  • 时间复杂度: O(mn)O(m*n)
  • 空间复杂度: O(mn)O(m*n)

参考