sudoku-leetcode37-Sudoku Solver做题感想

这题是一道backtrack的题目。

一开始我的思路用了set来表示每个空点能够填进去的数字,并对set做遍历,但后来发现这种解法虽然能过,但是复杂度太高了,最终我直接对每个点取‘0’到‘9’,看是否合适,其实感觉这种做法和对set不断erase的做法想法完全是一样的,只不过set的操作更复杂。可以得到一个结论是,当使用标准库和直接做的复杂度分析无明显差别时,如果直接做的算法更为直观,最好优先考虑比较直观的的算法。

另外一个很重要的点是:通过这道题,我发现,其实每次出错的地方往往都是我尝试着做改变、之前没有遇到过的地方。比如我今天写的这个算法:

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) {
        solve(board, 0, 0);
    }
private:
    int solve(vector<vector<char>>&board, int i, int j)
    {
        int find = 0;
        int x = i, y = j;
        int flag = 0;
        //找到下一个待填的位置
        for (x = i; x < 9; x++)
        {
            //设置y的初始值
            if (flag == 0)
                y = j;
            else
            {
                y = 0;
            }

            for (; y < 9; y++)
            {
                if (board[x][y] == '.')
                {
                    find = 1;
                    break;
                }
                
            }
            flag = 1;
            if (find == 1)
                break;
        }
        if (x == 9)
            return 1;
        //找出当前位置能够填入元素的集合,找到了就没关系了
        for(char in='1';in<='9';in++)
        {
            if(isvalid(board,x,y,in))
            {
                board[x][y]=in;
                if(solve(board,x,y))
                    return 1;
                board[x][y]='.';
            }
        }
        return 0;
    }
private:
    bool isvalid(vector<vector<char>>&board,int x,int y,char in)
    {
        for(int i=0;i<9;i++)
        {
            if(board[x][i]==in)return false;
            if(board[i][y]==in)return false;
            if(board[x/3*3+i/3][y/3*3+i%3]==in)return false;
        }
        return true;
    }
}
出错的地方就在上面那个找下一个空('.')处,还连续犯了两个错。第一次是每次初始化都将y从j开始,其实应该是第一次从j开始,后面都从0开始。第二次错误是,未设置flag。
这给我一个启发,一方面以后检查出错的地方应重点检查我现场创新的地方,比如上面的“寻找下一个空位置”;另一方面,如果通过练习,对这些可能出错的地方形成固定的写法,那么可以大大降低出错的几率,即使出错了,debug的速度也可以得到很大的提高。

猜你喜欢

转载自www.cnblogs.com/cool-breezer/p/10654297.html