LeetCode每日一题(Sudoku Solver)

本文介绍了一种使用深度优先搜索算法解决数独谜题的方法。通过建立行、列和3x3宫格的数字集合,寻找未填充单元格的可行数字,并递归地尝试填入。如果无法找到合适的数字,则回溯并尝试其他可能性。最终,成功找到了唯一解。此算法适用于解决具有唯一解的数独问题。
摘要由CSDN通过智能技术生成

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

Each of the digits 1-9 must occur exactly once in each row.
Each of the digits 1-9 must occur exactly once in each column.
Each of the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
The ‘.’ character indicates empty cells.

Example 1:

Input:
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”]
]
Output:
[
[“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”]
]

Explanation:
The input board is shown above and the only valid solution is shown below:

Constraints:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] is a digit or ‘.’.
  • It is guaranteed that the input board has only one solution.

题目看着挺吓人,但是实际上没有多难, 建立 3 个集合来分别保存行、列、方块当中所剩余的可以用的数字。比如 row_set[i] = { 1, 2, 3 }就表示第 i 行还剩下 1, 2 和 3 三个数字可选, col_set[j] = { 4, 5, 6 }则表示第 j 行还剩下 4, 5 和 6 三个数字可选, blk_set[i/3][j/3] = { 7, 8, 9 }则为 board[i][j]这个位置所处的方格里面还剩下 7, 8 和 9 三个数字可选。注意, 我们实际可选的数字实际是三个集合的交集, 因为我们要找到既不在行里出现过的,也不再列里出现过的,还不在方格里出现过的。如果交集是空集的话则证明不能成立,需要前面步骤重新填写。记着每填写一个格子,都要记得在三个集合里面去除掉填写的那个数字。


代码实现(Rust):

use std::collections::HashSet;
use std::iter::FromIterator;

impl Solution {
    fn dp(board: &mut Vec<Vec<char>>, row_set: Vec<HashSet<i32>>, col_set: Vec<HashSet<i32>>, blk_set: Vec<Vec<HashSet<i32>>>) -> bool {
        let mut row = None;
        let mut col = None;
        for i in 0..9 {
            for j in 0..9 {
                if board[i][j] == '.' {
                    row = Some(i);
                    col = Some(j);
                }
            }
        }
        if row.is_none() && col.is_none() {
            return true;
        }
        let row = row.unwrap();
        let col = col.unwrap();
        let inter: HashSet<i32> = row_set[row]
            .intersection(&col_set[col].intersection(&blk_set[row / 3][col / 3]).map(|v| *v).collect())
            .map(|v| *v)
            .collect();
        if inter.is_empty() {
            return false;
        }
        for v in inter {
            let mut r_set = row_set.clone();
            let mut c_set = col_set.clone();
            let mut b_set = blk_set.clone();
            r_set[row].remove(&v);
            c_set[col].remove(&v);
            b_set[row / 3][col / 3].remove(&v);
            board[row][col] = v.to_string().chars().nth(0).unwrap();
            if Solution::dp(board, r_set, c_set, b_set) {
                return true;
            }
        }
        board[row][col] = '.';
        return false;
    }

    pub fn solve_sudoku(board: &mut Vec<Vec<char>>) {
        let mut row_set: Vec<HashSet<i32>> = vec![HashSet::from_iter(1..=9); 9];
        let mut col_set: Vec<HashSet<i32>> = vec![HashSet::from_iter(1..=9); 9];
        let mut blk_set: Vec<Vec<HashSet<i32>>> = vec![vec![HashSet::from_iter(1..=9); 3]; 3];
        for row in 0..9 {
            for col in 0..9 {
                let val = board[row][col];
                if val != '.' {
                    let v = val.to_string().parse::<i32>().unwrap();
                    row_set[row].remove(&v);
                    col_set[col].remove(&v);
                    blk_set[row / 3][col / 3].remove(&v);
                }
            }
        }
        Solution::dp(board, row_set, col_set, blk_set);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值