有效的数独 图解题解
数独合法性验证,难点不是规则复杂,而是行、列、宫三个维度得同时查——一趟遍历搞定。
监考老师检查答题卡有没有填错:每格数字要同时过三关——这一行没重复、这一列没重复、这个小九宫没重复。老师备三本点名册(行/列/宫各一本),逐格核对,见到数字就查三本册子,没重复才记上去,有重复立刻判无效。一次遍历所有 81 格,三维同时查,完全不需要分三次扫。
这道题到底在问什么
- 输入
- board 见右图(含 . 的 9×9)
- 输出
- true(没有任何一行/列/小方块出现重复数字)
最优解:一步一步想明白
- 3记牢这套配置:行集合、列集合、宫集合各 9 个。每个数字要同时过三关,过了就登记进三处,撞了就立刻出局。
- 4开始扫描前:行、列、宫三套集合全是空的,已登记 0 个数字。指针从左上角第一格出发。
- 5指针走到第 0 行第 0 列,这格是 5。去查它的第 0 行、第 0 列、第 0 号宫——三套集合里现在都没有 5,三关都过。
- 6把 5 同时记进「第 0 行」「第 0 列」「第 0 号宫」三个集合,这格通过(变蓝)。已登记 1 个数字,继续往后扫。
- 7指针走到第 0 行第 1 列,这格是 3。去查它的第 0 行、第 1 列、第 0 号宫——三套集合里现在都没有 3,三关都过。
- 8把 3 同时记进「第 0 行」「第 1 列」「第 0 号宫」三个集合,这格通过(变蓝)。已登记 2 个数字,继续往后扫。
- 9指针走到第 0 行第 4 列,这格是 7。去查它的第 0 行、第 4 列、第 1 号宫——三套集合里现在都没有 7,三关都过。
- 10把 7 同时记进「第 0 行」「第 4 列」「第 1 号宫」三个集合,这格通过(变蓝)。已登记 3 个数字,继续往后扫。
- 11指针走到第 1 行第 0 列,这格是 6。去查它的第 1 行、第 0 列、第 0 号宫——三套集合里现在都没有 6,三关都过。
- 12把 6 同时记进「第 1 行」「第 0 列」「第 0 号宫」三个集合,这格通过(变蓝)。已登记 4 个数字,继续往后扫。
- 13指针走到第 1 行第 3 列,这格是 1。去查它的第 1 行、第 3 列、第 1 号宫——三套集合里现在都没有 1,三关都过。
- 14把 1 同时记进「第 1 行」「第 3 列」「第 1 号宫」三个集合,这格通过(变蓝)。已登记 5 个数字,继续往后扫。
- 15指针走到第 1 行第 4 列,这格是 9。去查它的第 1 行、第 4 列、第 1 号宫——三套集合里现在都没有 9,三关都过。
- 16把 9 同时记进「第 1 行」「第 4 列」「第 1 号宫」三个集合,这格通过(变蓝)。已登记 6 个数字,继续往后扫。
- 17指针走到第 1 行第 5 列,这格是 5。去查它的第 1 行、第 5 列、第 1 号宫——三套集合里现在都没有 5,三关都过。
- 18把 5 同时记进「第 1 行」「第 5 列」「第 1 号宫」三个集合,这格通过(变蓝)。已登记 7 个数字,继续往后扫。
- 19指针走到第 2 行第 1 列,这格是 9。去查它的第 2 行、第 1 列、第 0 号宫——三套集合里现在都没有 9,三关都过。
- 20把 9 同时记进「第 2 行」「第 1 列」「第 0 号宫」三个集合,这格通过(变蓝)。已登记 8 个数字,继续往后扫。
- 21指针走到第 2 行第 2 列,这格是 8。去查它的第 2 行、第 2 列、第 0 号宫——三套集合里现在都没有 8,三关都过。
- 22把 8 同时记进「第 2 行」「第 2 列」「第 0 号宫」三个集合,这格通过(变蓝)。已登记 9 个数字,继续往后扫。
- 23指针走到第 2 行第 7 列,这格是 6。去查它的第 2 行、第 7 列、第 2 号宫——三套集合里现在都没有 6,三关都过。
- 24把 6 同时记进「第 2 行」「第 7 列」「第 2 号宫」三个集合,这格通过(变蓝)。已登记 10 个数字,继续往后扫。
- 25指针走到第 3 行第 0 列,这格是 8。去查它的第 3 行、第 0 列、第 3 号宫——三套集合里现在都没有 8,三关都过。
- 26把 8 同时记进「第 3 行」「第 0 列」「第 3 号宫」三个集合,这格通过(变蓝)。已登记 11 个数字,继续往后扫。
- 27看个反例:假设第 0 行第 2 列也想填 5(标红那格)。可第 0 行已经登记过 5(左边高亮那格),一查集合就撞上——这种情况立刻判定无效。
- 28本题这张盘没有任何一处撞车,全程三关都过。继续扫完剩下的格子也都通过,最终判定:有效。
⚠️ 容易写错的地方
✗ 错:宫格编号算错,比如用 i*3+j
✓ 对:用 b = (i//3)*3 + j//3
宫是按 3×3 分块的,要先把行、列各除以 3 定位到哪一块,再编号 0-8
✗ 错:忘了跳过空格 '.',把点也塞进集合
✓ 对:遇到 '.' 直接 continue
空格不是数字,若把 '.' 也记录,多个空格会被误判成重复
✗ 错:只检查行和列,漏掉 3×3 宫
✓ 对:行、列、宫三关都要查
数独的核心约束之一就是小方块内不重复,漏了宫会把无效盘判成有效
完整代码(Python / C++ / Java)
Python
def isValidSudoku(board):
rows = [set() for _ in range(9)] # 9 行各一个集合
cols = [set() for _ in range(9)] # 9 列各一个集合
boxes = [set() for _ in range(9)] # 9 个 3x3 宫各一个
for i in range(9):
for j in range(9):
d = board[i][j]
if d == '.': # 空格跳过
continue
b = (i // 3) * 3 + j // 3 # 宫编号 0-8
if d in rows[i] or d in cols[j] or d in boxes[b]:
return False # 任一处撞 → 无效
rows[i].add(d); cols[j].add(d); boxes[b].add(d)
return TrueC++
bool isValidSudoku(vector<vector<char>>& board){
int rows[9][9]={0}, cols[9][9]={0}, box[9][9]={0};
for(int i=0;i<9;i++) for(int j=0;j<9;j++){
if(board[i][j]=='.') continue;
int d=board[i][j]-'1', b=(i/3)*3+j/3;
if(rows[i][d]||cols[j][d]||box[b][d]) return false;
rows[i][d]=cols[j][d]=box[b][d]=1;
}
return true;
}Java
public boolean isValidSudoku(char[][] board) {
boolean[][] rows=new boolean[9][9], cols=new boolean[9][9], box=new boolean[9][9];
for (int i=0;i<9;i++) for (int j=0;j<9;j++) {
if (board[i][j]=='.') continue;
int d=board[i][j]-'1', b=(i/3)*3+j/3;
if (rows[i][d]||cols[j][d]||box[b][d]) return false;
rows[i][d]=cols[j][d]=box[b][d]=true;
}
return true;
}复杂度
时间
O(1)
盘面固定 9×9,至多看 81 格、每格查/记 3 个集合,是常数次操作
空间
O(1)
27 个集合,每个最多装 9 个数字,总量固定,与输入规模无关
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 有效的数独 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么是 27 个集合?+
9 行各一个、9 列各一个、9 个 3×3 宫各一个,3×9=27。每个集合独立记录自己范围内已出现过的数字。
需要把数独解出来才能判断有效吗?+
不需要。本题只校验当前已填数字有没有违反「行/列/宫不重复」,是一次性的合法性检查,和求解是两回事。
能不能用一次遍历同时判三关,而不是扫三遍?+
可以,也推荐这么做。扫一遍、每格同时查并更新行/列/宫三个集合即可,时间不变、代码更简洁。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 有效的数独 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。