力扣 37.解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则: 

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

 回溯法:

我么创建数组来判断数字是否出现, 我们可以填入的数为1~9, 所以我们创建三个数组表示行,列和3*3的小方格

bool r[i][k];//表示第i行是否出现 k + 1
bool c[j][k];//表示第j列是否出现 k + 1
bool rc[i/3][j/3][k];//表示第(i/3, j/3)个九宫格是否出现 k + 1

 

我们首先对整个数独数组进行遍历,当我们遍历到第 i 行第 j 列的位置:

vector<pair<int, int>>v;//其中pair<int, int> 用来存还没有填入数字的<i, j> 位置

如果该位置是一个 '.',那么我们将其加入容器,用来进行递归操作

如果该位置是一个数字 x,那么我们要进行如下操作,表示该数字出现已经在i行,j列和(i/3, j/3)出现过。

int k = x - 1;
r[i][k] = true;
c[j][k] = true;
rc[i/3][j/3][k] = true;

当我们初始化原有数据后,进行遍历容器v,从v.begin()开始递归遍历,当递归到第 i 行第 j 列的位置时,我们枚举填入的数字 x。根据题目的要求,数字 x 不能和当前行、列、九宫格中已经填入的数字相同也就是:

int k = x - 1;
r[i][k] = false;
c[j][k] = false;
rc[i/3][j/3][k] = false;

以上三个值为false时,将x填入第 i 行第 j 列,当我们填入了数字 x 之后,我们要将上述的三个值都置为 true,并且继续对下一个空白格位置进行递归。在回溯到当前递归层时,我们还要将上述的三个值重新置为 false。

class Solution {
private:
    bool r[9][9];
    bool c[9][9];
    bool rc[3][3][9];
    bool flag;
    vector<pair<int, int>>v;
public:
    void dfs(vector<vector<char>>& board, int index) {
        if(index == v.size()) {
            flag = true;
            return;
        }

        int i = v[index].first;
        int j = v[index].second;
        for(int k = 0; k < 9 && !flag; k++) {
            if(!r[i][k] && !c[j][k] && !rc[i/3][j/3][k]) {
                r[i][k] = c[j][k] = rc[i/3][j/3][k] = true;
                board[i][j] = k + '0' + 1;
                dfs(board, index + 1);
                r[i][k] = c[j][k] = rc[i/3][j/3][k] = false;
            }
        }
    }
    void solveSudoku(vector<vector<char>>& board) {
        memset(r, false, sizeof(r));
        memset(c, false, sizeof(c));
        memset(rc, false, sizeof(rc));
        flag = false;

        for(int i = 0; i < 9; i++) {
            for(int j = 0; j < 9; j++) {
                if(board[i][j] == '.') {
                    v.push_back(pair<int, int>(i, j));
                }
                else {
                    int k = board[i][j] - '0' - 1;
                    r[i][k] = c[j][k] = rc[i/3][j/3][k] = true;
                }
            }
        }
        return dfs(board, 0);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值