持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情
37. 解数独
来源:力扣(LeetCode)
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
- 数字 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);
}
};
复杂度分析
- 时间复杂度:
- 空间复杂度: