LeetCode 37. Sudoku Solver|DFS算法

题目简介

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

Empty cells are indicated by the character ‘.’.

You may assume that there will be only one unique solution.

这里写图片描述
A sudoku puzzle…

这里写图片描述

题目分析

这道题目虽然是hard,但是算法角度来看这道题一点都不难。首先我是先做了一个easy的相关题目练手,顺带把有关这题的函数写了。也就是判断一个数独是否有效(含有空格的形况下),也就是对每行,每个九宫格,每列,进行检查有没有重复使用的数字,时间复杂度为O(N^2),看起来这个复杂度很可怕,但其实因为N非常小,几乎可以看成是常数级地运算。

算法分析

这道题一看就是用DFS的穷搜的方法,每个待定数字一个一个搜索,出现死路则回溯,时间复杂度看起来也是十分可怕O(N^N),但是实际上,由于N很小,以及在DFS期间剪掉了很多枝,所以在运行时间上来看,还是十分有效的。已经,这里在check上面可以有个小改进,实际上对新加入来的数字,只需要检验其所在的行、列和九宫格是否有效就可以了,不必对整个数独进行检验,在检验上的时间复杂度可以减少一个数量级,但是由于N很小,我就没有改了。


void print(vector<vector<char> > board){
    for(int i = 0 ; i < 9 ; i++){
        for(int j = 0 ; j < 9 ; j++)
        cout<<board[i][j]<<" ";
        cout<<endl;
    }
    cout<<endl;
}    


void initial_used(bool * used){
    for(int i = 0 ; i < 9 ; i ++)
    used[i] =false;
}
  bool isValidSudoku(vector<vector<char> >& board) {
        bool *used = new bool [9];
        // check row
        for (int i =0 ;  i < 9 ;i++){
               initial_used(used);
            for(int j = 0 ; j < 9 ; j++){
            if(board[i][j]!='.')
            {
                //cout<<board[i][j]-'0'<<endl;
                if(used[board[i][j]-'1']) return false;
                used[board[i][j]-'1'] =true;
            }
            } 
        }
        //check col
        for (int j =0 ;  j < 9 ;j++){
               initial_used(used);
            for(int i = 0 ; i < 9 ; i++){
            if(board[i][j]!='.')
            {
                if(used[board[i][j]-'1']) return false;
                used[board[i][j]-'1'] =true;
            } }
        }
        // check grid
        int beg[9][2] = {{0,0},{0,3},{0,6},{3,0},{3,3},{3,6},{6,0},{6,3},{6,6}};

        for(int k = 0 ;  k < 9 ; k++ ){
            int x = beg[k][0];
            int y = beg[k][1];
            initial_used(used);
            for(int i = 0 ;i<3;i++){
                for(int j = 0 ;j<3 ;j++){
                if(board[x+i][y+j]!='.')
                {
                    if(used[board[x+i][y+j]-'1']) return false;
                    used[board[x+i][y+j]-'1'] =true;
                } 
                }
            } 
        }

        delete[] used;
        return true;

}


void solve(vector<vector<char> >& board , int x , int y ,bool &yes){

    if(y==9){
        y= 0 ;x++;
    }
        if(x==9){
        yes = true;
        return ;
    } 

    while(board[x][y]!='.'){
    y++;

    if(y==9){
        y= 0 ;x++;
    }
        if(x==9){
        yes = true;
        return ;
    } 
    }
    //cout<<count++<<endl;
    //print(board);
    for(int letter = 0 ; letter< 9 ; letter ++){
            board[x][y]=letter+'1';
            if(isValidSudoku(board)){
                solve(board,x,y+1,yes);
                if(yes) return ;
            }

    }
        board[x][y] = '.';
}


void solveSudoku(vector<vector<char> > & board) {

    bool yes = false;
    int x , y;
    for(int i = 0 ; i< 9 ;i++)
        for(int j = 0 ; j < 9;j++)
        if(board[i][j]=='.'){
            x = i;
            y= j;
            goto solve_pro;
        }
    solve_pro:

     solve(board,x,y,yes); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值