题解 | 数独

数独

http://www.nowcoder.com/practice/5e6c424b82224b85b64f28fd85761280

解法一:递归回溯

递归参数:

  • 因为解数独找到一个符合的条件(就在树的叶子节点上)立刻就返回,相当于找从根节点到叶子节点一条唯一路径,所以需要使用bool返回值,

终止条件:

  • 递归的下一层的棋盘一定比上一层的棋盘多一个数,等数填满了棋盘自然就终止(填满当然好了,说明找到结果了),所以不需要终止条件!

判断棋盘是否合法有如下三个维度:

  • 同行是否重复
  • 同列是否重复
  • 9宫格里是否重复

图片说明

图片;来自Carl大佬的[D码随想录]

C++参考代码:

class Solution {
private:
bool backtracking(vector<vector<char>>& board) {
    for (int i = 0; i < board.size(); i++) {        // 遍历行
        for (int j = 0; j < board[0].size(); j++) { // 遍历列
            if (board[i][j] != '.') continue;
            for (char k = '1'; k <= '9'; k++) {     // (i, j) 这个位置放k是否合适
                if (isValid(i, j, k, board)) {
                    board[i][j] = k;                // 放置k
                    if (backtracking(board)) return true; // 如果找到合适一组立刻返回
                    board[i][j] = '.';              // 回溯,撤销k
                }
            }
            return false;                           // 9个数都试完了,都不行,那么就返回false
        }
    }
    return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
    for (int i = 0; i < 9; i++) { // 判断行里是否重复
        if (board[row][i] == val) {
            return false;
        }
    }
    for (int j = 0; j < 9; j++) { // 判断列里是否重复
        if (board[j][col] == val) {
            return false;
        }
    }
    int startRow = (row / 3) * 3;
    int startCol = (col / 3) * 3;
    for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
        for (int j = startCol; j < startCol + 3; j++) {
            if (board[i][j] == val ) {
                return false;
            }
        }
    }
    return true;
}
public:
    void solveSudoku(vector<vector<char>>& board) {
        backtracking(board);
    }
};

复杂度分析:

时间复杂度:
由于这些方法均以递归 + 回溯为基础,算法运行的时间(以及时间复杂度)很大程度取决于给定的输入数据,而我们很难找到一个非常精确的渐进紧界。因此这里只给出一个较为宽松的渐进复杂度上界 图片说明 ,即最多有9×9 个空白格,每个格子可以填[1,9] 中的任意整数。

复杂度参考:LeetCode-Solution

空间复杂度:复杂度为 O(1) 在固定 9*9 的棋盘里,复杂度不随数据变化而变化。

解法二:位运算

经常玩数独的可能知道,在填数字的时候一般都是选择那些可填数字比少的位置来填,所以这里也可以使用这种方式。这里为了便于计算,稍微修改了一点,每行每列每个单元格都使用一个int数字来记录,因为int类型是32位,而数独的行和列以及单元格大小都是9,所以使用int来存储足够了,这里只使用int类型的低9位来存储。举个简单的例子,比如第一行已经填了3个数字,比如示例中的5,3,7。那么我们就可以使用一个int类型的数字来表示
图片说明

该解法参考作者:sdwwld

Java参考代码:

public class Solution {
               //数独的长宽大小
        final int N = 9;
        //行
        private int[] rows = new int[N];
        //列
        private int[] cols = new int[N];
        //单元格
        private int[][] cells = new int[3][3];

        public void solveSudoku(char[][] board) {
            //统计未填的个数
            int count = 0;
       

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

小白专属-牛客题解 文章被收录于专栏

专注于牛客平台编程题题解,文字+图解。内容很细,小白友好系列

全部评论

相关推荐

11-13 20:16
已编辑
厦门理工学院 软件测试
专业嗎喽:硕佬,把学校背景放后面几段,学校背景双非还学院,让人看了就不想往下看。 把实习经历和个人奖项放前面,用数字化简述自己实习的成果和掌握的技能,比如负责项目一次通过率90%,曾4次发现项目潜在问题风险为公司减少损失等等
点赞 评论 收藏
分享
10-19 10:28
已编辑
西南石油大学 后端工程师
团孝子已上线feeling:面了很多家公司,能感受到目前只有小公司+外包喜欢问八股。大厂虽然也问八股,但是是从实习、项目中进行提问,并且大厂会问很深,面试官也会对你的回答进行思考➕追问,所以准备大厂面试前一定要备好相关资料。对于算法,我做的是codetop前100+力扣hot100+力扣高频150,面试中实感hot100就足够,基本上只要是hot100就秒答。对于项目和八股,我做的也是烂大街的星球项目,八股则是看小林和问ai,自己也写了很多技术博客和画了很多思维导图,并且自己也尝试用嘴巴说出来,不只停留于纸面。运气也很重要,必须要让面试官/HR看到简历才行,所以建议投递时间是下午两点。tl:第一岗位9.9&nbsp;投递9.10&nbsp;一面(一面评价:最近见过最强的大三,结束五分钟后约二面,都晚上九点了不下班吗)9.11&nbsp;二面(三道算法a出两道,反问评价:经验不够等横向,我实习生要啥经验)9.21挂(实习时间过短+其他原因,想要一年实习的,为什么不招个正职)第二岗位10.10投递10.11约面(主管打电话,说看到我之前投递记录了想要我挂qa职进去干后端,同意)10.14&nbsp;一面(无八股,主动说确实很强,意愿很强)10.16&nbsp;oc其余,友邦,东软,东华,惠择,用友oc已拒京东测开一面挂(投后端被测开捞)腾讯测试已拒(投后端被测开捞)ps:表扬惠择的主管面,没怎么问技术(可能是一面面试官沟通过了),全程一起讲大道理,解答了心中很多疑惑,也告诉我以面试官角度来看怎么选候选人,如果可以下次一定选惠择
HeaoDng:美团好像可以触发一面通
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务