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,那麼後面那一個空位就無論如何也填不了了。而且如果在程序中不對這種情況進行檢查的話,可能要等到搜索到很深的地方纔能知道這個衝突。但如果是從可填數目最少的空位開始填,就絕對不會產生這種衝突(除非這個數獨不可解)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章