Sudoku Solver

一. Sudoku Solver

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…

这里写图片描述

…and its solution numbers marked in red.

Difficulty:Hard

TIME:35MIN

解法

这道题似乎除了搜索之外,没有特别好的解法,因此我直接写了一个最普通的搜索(没有任何优化),期待着会超时,然而并没有。

搜索的思想当然很简单,就是依次从左到右遍历,发现一个可以填的空位,就选择所有可以填的数字依次填入,当全部填好数字之后,就返回true,否则返回false。

bool dfs(vector<vector<char>>& board) {
    vector<char> v(10, 0);
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            if (board[i][j] == '.') {
                for (int k = 0; k < 9; k++) {
                    if (board[i][k] != '.')
                        v[board[i][k] - '0'] = 1;
                    if (board[k][j] != '.')
                        v[board[k][j] - '0'] = 1;
                    if (board[i / 3 * 3 + k / 3][j / 3 * 3 + k % 3] != '.')
                        v[board[i / 3 * 3 + k / 3][j / 3 * 3 + k % 3] - '0'] = 1;
                }
                for (int k = 1; k <= 9; k++) {
                    if (v[k] == 0) {
                        board[i][j] = k + '0';
                        if (dfs(board)) //如果数独已经解决,就直接返回
                            return true;
                        board[i][j] = '.';
                    }
                }
                return false;
            }
        }
    }
    return true; //程序运行到这里说明这个数独已经解决了
}
void solveSudoku(vector<vector<char>>& board) {
    dfs(board);
}

代码的时间复杂度为 O(9n) ,其中n为不确定的位置个数。

优化

虽然这样的解法能过LeetCode,但显然并不是一个特别好的解法,如果是我们自己去解决数独,当然不会从左到右依次遍历,找到空位就填。一般情况下我们都是去找能的填的数字比较少的空位来填,比如某个空位只能填一个数字,那么我们就会优先填那个空位。

因此,这道题最大的可以优化的地方就是,尽量降低搜索树前面结点分叉的数目(把分叉多的放到靠近叶结点的位置,把分叉少的放到靠近根结点的位置)。通过这样的处理,虽然时间复杂度是一样的,但是在解决实际问题的时候速度快了不是一点半点(无形中就减了很多枝)。

而且,从最少可填数目的空位开始填还可以避免冲突的产生,比如有同一行的两个空位,一个可以填3和4,一个只能填3,如果从前面的空位填3,那么后面那一个空位就无论如何也填不了了。而且如果在程序中不对这种情况进行检查的话,可能要等到搜索到很深的地方才能知道这个冲突。但如果是从可填数目最少的空位开始填,就绝对不会产生这种冲突(除非这个数独不可解)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值