Leetcode进阶之路——Sudoku

本文介绍两道与数独相关的题
第一题 36. Valid Sudoku

Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
1. Each row must contain the digits 1-9 without repetition.
2. Each column must contain the digits 1-9 without repetition.
3. Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.
数独
The Sudoku board could be partially filled, where empty cells are filled with the character ‘.’.

Example 1:
Input:
[
[“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: true

Example 2:
Input:
[
[“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”]
]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being
modified to 8. Since there are two 8’s in the top left 3x3 sub-box, it is invalid.

这题的题意是给你一个二维向量,代表一个数独,其中的’.’代表空白,要求验证所给数独是否是合理的。注意一点,这里只要求验证合理性,而不需要判断是否有解,我之前是先做了下面的一道,把它拿过来是Wrong
这道题理解了这一点后思路就明确了:只要依次判断九行、九列以及九个九宫格是否有重复数字即可,代码如下:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        bool res = true;
        //分别代表每列每行和每个九宫格的数字
        int cols[10] = { 0 }, rows[10] = { 0 }, cubes[10] = { 0 };
        int nums[10] = { 0 };
        for (int i = 0; i < 9; ++i)
        {
            memset(rows, 0, sizeof(rows));
            memset(cols, 0, sizeof(cols));
            for (int j = 0; j < 9; ++j)
            {
                //若一个数字在行或列中出现两次,则直接return false
                int col = board[i][j], row = board[j][i];
                if (col != '.')
                {
                    cols[col - '0']++;
                    if (cols[col - '0'] > 1) return false;
                }
                if (row != '.')
                {
                    rows[row - '0']++;
                    if (rows[row - '0'] > 1) return false;
                }
            }
        }
        for(int i = 0; i < 9; i += 3)
            for (int j = 0; j < 9; j += 3)
            {
                memset(cubes, 0, sizeof(cubes));
                for(int m = 0; m < 3; ++m)
                    for (int n = 0; n < 3; ++n)
                    {
                        int num = board[i + m][j + n];
                        if (num != '.')
                        {
                            cubes[num - '0']++;
                            if (cubes[num - '0'] > 1) return false;
                        }
                    }
            }
        return true;
    }
};

当然,从我之前做ACM的角度,这道题非常不”严谨”… 特别对于Valid这个词的用法…有个测试用例是这样的:
错误样例
其实我们一眼就看出来是“错”的,但根据我们的代码应该输出true,因此就像最开始说的,要区分“Valid”和有解

那么第二道就来了,求解数独 37. Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells.
A sudoku solution must satisfy all of the following rules:
1. Each of the digits 1-9 must occur exactly once in each row.
2. Each of the digits 1-9 must occur exactly once in each column.
3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character ‘.’.
数独求解

题意同样给定一个二维向量,求解该数独。
我这里用的是DFS的解法,也就是先一条路走到黑,要是发现哪个节点已经无法填数字了,再回溯到上一轮重新填写。代码如下,解法都在注释中:

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) 
    {
        dfs(board, 0);
    }
    //len代表已经填好的位置数量
    bool dfs(vector<vector<char>>& board, int len)
    {
        //len=81表示全部填好,直接返回true即可
        if (len == 81) return true;
        //自己构建一下会发现,len/9即行号,len%9为列号
        int i = len / 9, j = len % 9;
        if (board[i][j] != '.')
        {
            return dfs(board, len + 1);
        }
        //flag数组储存所有已经被使用过的数字
        bool flag[10] = { false };
        memset(flag, true, sizeof(flag));
        //通过valid函数,将已经使用过的数字置false
        valid(flag, board, i, j);
        for (int l = 1; l < 10; ++l)
        {
            //只有1~9可以填,若flag为true,即表示可以使用
            if (flag[l])
            {
                //直接赋值该数字,并进行下一轮遍历
                board[i][j] = l + '0';
                if (dfs(board, len + 1))
                    return true;
            }
        }
        //若发现从1~9都不能成功,就说明前一轮或几轮中有错误的填写,需把当前位置重置'.',并返回到上一轮
        board[i][j] = '.';
        return false;
    }

    void valid(bool flag[], vector<vector<char>> board, int i, int j)
    {
        //判断第i行第j列的元素所在行列以及其所在的九宫格已经有哪些数字
        for (int k = 0; k < 9; ++k)
        {
            if (board[i][k] != '.')
            {
                flag[board[i][k] - '0'] = false;
            }
            if (board[k][j] != '.')
            {
                flag[board[k][j] - '0'] = false;
            }

        }
        i /= 3, j /= 3;
        for(int k = 0; k < 3; ++k)
            for (int m = 0; m < 3; ++m)
            {
                if (board[i * 3 + k][j * 3 + m] != '.')
                {
                    flag[board[i * 3 + k][j * 3 + m] - '0'] = false;
                }
            }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值