Medium
题目描述
判断一个 9 x 9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
- 数字
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"]]
输出:true
示例 2:
输入:board =
[["8","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"]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
提示:
board.length == 9board[i].length == 9board[i][j]是一位数字(1-9)或者'.'
解题思路
解题思路
这道题需要验证数独是否有效,主要有两种思路:
方法一:三次遍历
最直观的方法是分别验证三个条件:
- 遍历每一行,检查是否有重复数字
- 遍历每一列,检查是否有重复数字
- 遍历每个3x3子方格,检查是否有重复数字
方法二:一次遍历(推荐)
更高效的方法是只遍历一次,同时检查三个条件。我们可以使用三个二维数组或哈希表来记录:
rows[i][num]:第i行是否已出现数字numcols[j][num]:第j列是否已出现数字numboxes[k][num]:第k个3x3子方格是否已出现数字num
关键是如何计算3x3子方格的索引:对于位置(i,j),其所在的子方格索引为 k = (i/3)*3 + j/3。
遍历过程中,如果发现某个数字在对应的行、列或子方格中已经存在,则返回false;否则标记该数字已出现。遍历完成后返回true。
这种方法时间复杂度为O(1)(因为数独大小固定为9x9),空间复杂度也为O(1)。
代码实现
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector<vector<bool>> rows(9, vector<bool>(9, false));
vector<vector<bool>> cols(9, vector<bool>(9, false));
vector<vector<bool>> boxes(9, vector<bool>(9, false));
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '1';
int boxIndex = (i / 3) * 3 + j / 3;
if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
return false;
}
rows[i][num] = true;
cols[j][num] = true;
boxes[boxIndex][num] = true;
}
}
}
return true;
}
};
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [[False] * 9 for _ in range(9)]
cols = [[False] * 9 for _ in range(9)]
boxes = [[False] * 9 for _ in range(9)]
for i in range(9):
for j in range(9):
if board[i][j] != '.':
num = int(board[i][j]) - 1
box_index = (i // 3) * 3 + j // 3
if rows[i][num] or cols[j][num] or boxes[box_index][num]:
return False
rows[i][num] = True
cols[j][num] = True
boxes[box_index][num] = True
return True
public class Solution {
public bool IsValidSudoku(char[][] board) {
bool[,] rows = new bool[9, 9];
bool[,] cols = new bool[9, 9];
bool[,] boxes = new bool[9, 9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '1';
int boxIndex = (i / 3) * 3 + j / 3;
if (rows[i, num] || cols[j, num] || boxes[boxIndex, num]) {
return false;
}
rows[i, num] = true;
cols[j, num] = true;
boxes[boxIndex, num] = true;
}
}
}
return true;
}
}
var isValidSudoku = function(board) {
const rows = Array.from({length: 9}, () => Array(9).fill(false));
const cols = Array.from({length: 9}, () => Array(9).fill(false));
const boxes = Array.from({length: 9}, () => Array(9).fill(false));
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
if (board[i][j] !== '.') {
const num = parseInt(board[i][j]) - 1;
const boxIndex = Math.floor(i / 3) * 3 + Math.floor(j / 3);
if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
return false;
}
rows[i][num] = true;
cols[j][num] = true;
boxes[boxIndex][num] = true;
}
}
}
return true;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(1) | 数独大小固定为9x9,遍历81个格子 |
| 空间复杂度 | O(1) | 使用固定大小的数组,9x9x3=243个布尔值 |