leetcode 37.解数独

leetcode 37.解数独

题干

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

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

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。

Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

题解

dfs+回溯算法
* 回溯算法的核心在于条件重新置false的语句的位置
* 第一遍写的时候语句A被我放在了位置B,这样写的结果是:一旦在填入数字进行后续的递归时遇到了不满足if条件的情况,就会将出现标记置false的情况,比如在一轮递归的for0-8时,
这个位置只能填8,写在外面就会导致把0-7的标记全部记false,这明显是错的。
* 将语句A放在位置A的原因是如果以这个数为起点的递归在后续出现了无答案的情况,会回到位置A使用下一个数进行第二轮递归(即回溯算法的本意),所以语句A的作用实际上是对错误答案的消除,
所以应该与数字一一对应

class Solution {
public:
    bool line[9][9];
    bool column[9][9];
    bool block[9][9];
    bool finish = false;
    vector<pair<int,int>> space;
    void dfs(vector<vector<char>>& board,int pos){
        if(pos==space.size())
        {
            finish = true;
            return;
        }
        auto [x,y] = space[pos];
        for(int digit=0;digit<9 && !finish;digit++)
        {
            //cout<<x<<' '<<y<<' '<<digit<<endl;
            if(line[x][digit]==false && column[y][digit]==false && block[x/3*3+y/3][digit]==false)
            {
                line[x][digit] = column[y][digit] = block[x/3*3+y/3][digit] = true;
                board[x][y] = digit + '0' + 1;
                dfs(board,pos+1);
                line[x][digit] = column[y][digit] = block[x/3*3+y/3][digit] = false;//!!!!!!!!!!!!!!!!!!!!!!!!!!!就是这句语句,记为语句A,位置A
            }
            //board[x][y] = '.';
            //原来语句A所在的位置,记为位置B
        }
    }
    void solveSudoku(vector<vector<char>>& board) {

        memset(line,false,sizeof(line));
        memset(column,false,sizeof(column));
        memset(block,false,sizeof(block));
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
            {
                if(board[i][j]!='.')
                {
                    int num = board[i][j] - '1';//这里的num是实际数字-1,方便数组操作
                    int blockIndex = i / 3 * 3 + j / 3;
                    //cout<<blockIndex<<' ';
                    line[i][num] = column[j][num] = block[blockIndex][num] = true;
                }
                else
                    space.emplace_back(i,j);
            }
        }
        dfs(board,0);
    }
};

/*block
0 1 2
3 4 5
6 7 8
*/

一次改进:
* 仿照了上次组合问题用二进制保存状态的方法,把line column block变为一位数组,缩短了运行时间,
* 尼玛力扣的官方题解运行好快 ~表示按位取反

class Solution {
public:
    int line[9];
    int column[9];
    int block[9];
    bool finish = false;
    vector<pair<int,int>> space;
    void dfs(vector<vector<char>>& board,int pos){
        if(pos==space.size())
        {
            finish = true;
            return;
        }
        auto [x,y] = space[pos];
        for(int digit=0;digit<9 && !finish;digit++)
        {
            //cout<<x<<' '<<y<<' '<<digit<<endl;
            int mask = 1<<digit;
            if((line[x]&mask)==0 && (column[y]&mask)==0 && (block[x/3*3+y/3]&mask)==0)
            {
                line[x] += mask;
                column[y] += mask;
                block[x/3*3+y/3] += mask;
                board[x][y] = digit + '0' + 1;
                dfs(board,pos+1);
                line[x] -= mask;
                column[y] -= mask;
                block[x/3*3+y/3] -= mask;
            }
            //board[x][y] = '.';
            
        }
    }
    void solveSudoku(vector<vector<char>>& board) {

        memset(line,false,sizeof(line));
        memset(column,false,sizeof(column));
        memset(block,false,sizeof(block));
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
            {
                if(board[i][j]!='.')
                {
                    int num = board[i][j] - '1';//这里的num是实际数字-1,方便数组操作
                    int blockIndex = i / 3 * 3 + j / 3;
                    //cout<<blockIndex<<' ';
                    line[i] += 1<<num;
                    column[j] += 1<<num;
                    block[blockIndex] += 1<<num;;
                }
                else
                    space.emplace_back(i,j);
            }
        }
        dfs(board,0);
    }
};

/*block
0 1 2
3 4 5
6 7 8
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值