题目:

37. Sudoku Solver

37. Sudoku Solver

解答:

是很久以前做的了,代码有点长。。有空要去重新改造下。

简单的思路是这样的:

  • 建立一个9*9的数独可选数集,每个集合包含1-9九个数
  • 根据已有数独数据,如果是确定的数据,将集合数修改为只包含一个数
  • 根据数独的已有数,对行、列、中等格的9个数进行筛选,每个单元的集合数筛除该单元不可存在的数。
  • 如果筛选后结果只有一个可能,那这个位置的数也确定了。
  • 如果经过筛选后,没有新增确定数,那么,将当前数独可选集压入栈中,然后按序选出第一个不确定数,将其设定为第一个。继续上面步骤,如果此时,发现有冲突了,则退回栈中可选数集,改为第二个,如果继续遇到没有新增确定数,那么将此时的可选数集压入栈中,按序选出下一个不确定数。
  • 可选数集内所有数均只有一个的时候,数独填充完毕。

代码:

class Solution {
public:
    struct ShuDuIndex
    {
        int i;
        int j;
        int index;
    };
    void initHelpData(vector<vector<list<int>>>& t)
    {
        t.clear();
        list<int> tmp;
        for(int i = 1;i <= 9;++i)
            tmp.push_back(i);
        for(int i = 0;i < 9; ++i)
        {
            vector<list<int>> listtmp;
            for(int j = 0;j < 9;++j)
            {
                listtmp.push_back(tmp);
            }
            t.push_back(listtmp);
        }
    }
    bool HasFinished(vector<vector<int>>& t)
    {
        for(int i = 0;i < 9;++i)
            for(int j = 0;j < 9; ++j)
                if(t[i][j] == 0)
                    return false;
        return true;
    }
    void updateHelpData(vector<vector<int>>& t, vector<vector<list<int>>>& helper)
    {
        for(int i = 0;i < 9; ++i)
            for(int j = 0;j < 9; ++j){
                if(t[i][j] != 0){
                    helper[i][j].clear();
                    helper[i][j].push_back(t[i][j]);
                }
            }
    }
    int freshHelperData(vector<vector<int>>& shudu, vector<vector<list<int>>>& t, int indexx, int indexy)
    {
        int num = shudu[indexx][indexy];
        for(int index = 0;index < 9; ++index){
            if(shudu[indexx][index] == 0 ){
                list<int>::iterator it = find(t[indexx][index].begin(),
                        t[indexx][index].end(), num);
                if(it != t[indexx][index].end()){
                    t[indexx][index].erase(it);
                    if(t[indexx][index].empty())    {
                        //cout << "line4 empty " << indexx << " " << index << endl;
                        return -1;
                    }
                }
            }
            if(shudu[index][indexy] == 0){
                list<int>::iterator it = find(t[index][indexy].begin(), t[index][indexy].end(), num);
                if(it != t[index][indexy].end()){
                    t[index][indexy].erase(it);
                    if(t[index][indexy].empty())    {
                        //cout << "line5 empty " << index << " " << indexy << endl;
                        return -1;
                    }
                }
            }
        }
        for(int m = indexx - indexx % 3;m < indexx - indexx % 3 + 3; ++m)
            for(int n = indexy - indexy % 3;n < indexy - indexy % 3 + 3; ++n){
                if(shudu[m][n] == 0){
                    list<int>::iterator it = find(t[m][n].begin(), t[m][n].end(), num);
                    if(it != t[m][n].end()){
                        t[m][n].erase(it);
                        if(t[m][n].empty()) {
                            //cout << "line6 empty " << m << " " << n << endl;
                            return -1;
                        }
                    }
                }
            }
        return 0;
    }
    int changeShuDu(vector<vector<int>>& shudu, vector<vector<list<int>>>& t)
    {
        bool hasChanged = false;
        for(int i = 0;i < 9; ++i)
            for(int j = 0;j < 9;++j){
                if(shudu[i][j] != 0){
                    for(int k = 0;k < 9; ++k){
                        if(k != i){
                            list<int>::iterator it = find(t[k][j].begin(), t[k][j].end(), shudu[i][j]);
                            if(it != t[k][j].end()){
                                t[k][j].erase(it);
                                if(t[k][j].empty()) {
                                    //cout << "list1 empty " << k << " " << j << endl;
                                    return -1;
                                }
                            }
                        }
                    }
                    for(int k = 0;k < 9; ++k){
                        if(k != j){
                            list<int>::iterator it = find(t[i][k].begin(), t[i][k].end(), shudu[i][j]);
                            if(it != t[i][k].end()){
                                t[i][k].erase(it);
                                if(t[i][k].empty()) {
                                    //cout << "line2 empty " << i << " " << k << endl;
                                    return -1;
                                }
                            }
                        }
                    }
                    int indexx = i - i % 3;
                    int indexy = j - j % 3;
                    for(int k = indexx;k < indexx + 3;++k)
                        for(int d = indexy;d < indexy + 3;++d){
                            if(!(k == i && d == j)){
                                list<int>::iterator it = find(t[k][d].begin(), t[k][d].end(), shudu[i][j]);
                                if(it!=t[k][d].end()){
                                    t[k][d].erase(it);
                                    if(t[k][d].empty()) {
                                        //cout << "line3 empty " << k << " " << d << endl;
                                        return -1;
                                    }
                                }
                            }
                        }
                    }//end if(shudu[i][j] != 0)
                }// for(int j = 0;j < 9;++j)
                for(int i = 0;i < 9; ++i)
                    for(int j = 0;j < 9; ++j)
                        if(shudu[i][j] == 0 && t[i][j].size() == 1){
                            //cout << "i,j " << i << " " << j << endl;
                            shudu[i][j] = *(t[i][j].begin());
                            if(freshHelperData(shudu, t, i, j)<0)   return -1;
                            hasChanged = true;
                        }

                for(int i = 0;i < 9; ++i){      //横着的,用排除法
                    for(int num = 1;num <= 9; ++num){
                        int index = -1, numcnt = 0;
                        bool stop = false;
                        for(int j = 0;j < 9; ++j){
                            if(shudu[i][j] == num){
                                stop = true;
                                break;
                            }
                            list<int>::iterator it = find(t[i][j].begin(), t[i][j].end(), num);
                            if(it != t[i][j].end()){
                                index = j;
                                numcnt++;
                            }
                        }
                        if(stop) continue;
                        if(numcnt == 1){
                            t[i][index].clear();
                            t[i][index].push_back(num);
                            shudu[i][index] = num;
                            if(freshHelperData(shudu, t, i, index)<0)   return -1;
                            hasChanged = true;
                        }
                    }
                }
                for(int i = 0;i < 9; ++i){      //竖着的,用排除法
                    for(int num = 1;num <= 9; ++num){
                        int index = -1, numcnt = 0;
                        bool stop = false;
                        for(int j = 0;j < 9; ++j){
                            if(shudu[j][i] == num){
                                stop = true;
                                break;
                            }
                            list<int>::iterator it = find(t[j][i].begin(), t[j][i].end(), num);
                            if(it != t[j][i].end()){
                                index = j;
                                numcnt++;
                            }
                        }
                        if(stop)    continue;
                        if(numcnt == 1){
                            t[index][i].clear();
                            t[index][i].push_back(num);
                            shudu[index][i] = num;
                            if(freshHelperData(shudu, t, index, i)<0)   return -1;
                            hasChanged = true;
                        }
                    }
                }
                for(int i = 0;i < 9;i = i + 3){
                    for(int j = 0;j < 9;j = j + 3){
                        for(int num = 1;num <= 9;++num){
                            int x = -1, y = -1, numcnt = 0;
                            bool stop = false;
                            for(int indexx = i;indexx < i + 3;++indexx)
                                for(int indexy = j;indexy < j + 3;++indexy){
                                    if(shudu[indexx][indexy] == num){
                                        stop = true;
                                        break;
                                    }
                                    list<int>::iterator it = find(t[indexx][indexy].begin(), t[indexx][indexy].end(), num);
                                    if(it != t[indexx][indexy].end()){
                                        x = indexx;
                                        y = indexy;
                                        numcnt++;
                                    }
                                }
                                if(stop)    continue;
                                if(numcnt == 1){
                                    t[x][y].clear();
                                    t[x][y].push_back(num);
                                    shudu[x][y] = num;
                                    if(freshHelperData(shudu, t, x, y)<0)   return -1;
                                    hasChanged = true;
                                }
                }
            }
        }
        return hasChanged ? 1 : 0;
    }
    
    void initShudu(vector<vector<char>>& board, vector<vector<int>>& shudu){
        for(int i = 0;i < 9; ++i){
            vector<int> vec;
            for(int j = 0;j < 9; ++j){
                vec.push_back(board[i][j] == '.' ? 0 : board[i][j] - '0');
            }
            shudu.push_back(vec);
        }
    }
    void solveSudoku(vector<vector<char>>& board) {
        vector<vector<int>> shudu;
        initShudu(board, shudu);
        vector<vector<list<int>>> t;
        initHelpData(t);
        updateHelpData(shudu, t);
        int count = 0;
        stack<ShuDuIndex> stkIndex;
        stack<vector<vector<int>> > stkShuDu;
        stack<vector<vector<list<int>>> > stkT;
        while(count++ < 1000){
             int changeStatus = changeShuDu(shudu, t);
             int indexx = -1, indexy = -1, indexz = -1, listsize = 100;
             if(changeStatus == 1)  continue;
             else if(changeStatus == -1){
                 while(true){
                     if(stkShuDu.empty()){
                         //ut << "all choice invalid stack empty fail" << endl;
                         return ;
                     }
                     shudu = stkShuDu.top();
                     t = stkT.top();
                     ShuDuIndex sd = stkIndex.top();
                     if(t[sd.i][sd.j].size() == sd.index+1){
                         //cout << "choice invalid goto next stack" << endl;
                         stkShuDu.pop();
                         stkT.pop();
                         stkIndex.pop();
                         continue;
                     }
                     stkIndex.pop();
                     sd.index = sd.index+1;
                     stkIndex.push(sd);
                     indexx = sd.i;
                     indexy = sd.j;
                     indexz = sd.index;
                     break;
                 }
             }
             else{
                 if(HasFinished(shudu))  break;
                 for(int i = 0;i < 9; ++i){
                     for(int j = 0;j < 9; ++j){
                         if(shudu[i][j] == 0 && t[i][j].size() < listsize){
                             indexx = i, indexy = j, listsize = t[i][j].size();
                         }
                     }
                 }
                 ShuDuIndex sd;
                 sd.i = indexx;
                 sd.j = indexy;
                 sd.index = 0;
                 indexz = 0;
                 
                 stkShuDu.push(shudu);
                 stkT.push(t);
                 stkIndex.push(sd);
                 //cout << "push data to stack" << endl;
             }
             int num = -1;
             list<int>::iterator it = t[indexx][indexy].begin();
             for(int i = 0;i < indexz; ++i) ++it;
             num = *it;
             shudu[indexx][indexy] = num;
             t[indexx][indexy].clear();
             t[indexx][indexy].push_back(num);
        }
        for(int i = 0;i < 9; ++i)
            for(int j = 0;j < 9; ++j)
                board[i][j] = '0' + shudu[i][j];
    }
};

更新会同步在我的网站更新(https://zergzerg.cn/notes/webnotes/leetcode/index.html)

相关文章: