1. 程式人生 > >演算法練習week4--leetcode37

演算法練習week4--leetcode37

題目描述

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

  1. Each of the digits 1-9 must occur exactly once in each row.
  2. Each of the digits 1-9 must occur exactly once in each column.
  3. Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.

Empty cells are indicated by the character '.'.


A sudoku puzzle...


...and its solution numbers marked in red.

Note:

  • The given board contain only digits 1-9
     and the character '.'.
  • You may assume that the given Sudoku puzzle will have a single unique solution.
  • The given board size is always 9x9.

     

題目分析

首先這道題的思路的比較直觀,我們先把空著的格子統計出來放到一個ArrayList<int> 裡面, 然後開始運用dfs。每當填入一個數字的時候我們需要用isValid來驗證,只有不衝突的情況下才能新增進格子裡。

題意

:寫一個程式解決數獨問題,即在給定的數獨上面填充數值,使得數獨滿足有效條件,假定只有唯一解。

解題思路:深度遍歷的過程,從開始一直掃描,直到遇到空字元,便可開始填數字,該位置的數字從1~9依次遍歷,不行的時候就回退。


演算法設計

1. checkValid方法中position是位置,位置從0開始,直到81時結束,根據position可以確定此時的行和列。該方法的含義是判斷在給position位置填寫了數之後,行列以及塊是否合法,即是否會出現相同的數字出現

2. solve方法是核心:從開始的位置一直掃描,直到遇到非數字,然後開始遞迴,.的位置有可能是任何數字,然後從1-9開始試,將該位置的值設為1-9中的其中一個之後,呼叫checkValid方法判斷該位置為填充上值之後是否合法,如果合法,繼續下一個位置的判斷,即開始遞迴。當該遞迴返回時,如果是false,則表示剛才的位置數字填錯了,需要重新填,則先恢復,在繼續試探。直到返回true為止,否則返回false

3 可以考慮“先放置,再判斷”的方案。

4 所有的方案(k從1到9)完畢之後,應該返回錯誤,這個是不應該被忽略的。

5 最後一點需要注意的是,當i,j迴圈完畢之後,實際上是最終/最底層的一次迴圈,表明已經解出了sudoku,返回ture.

 

演算法實現

class Solution
{
public:
    bool isValid(vector<vector<char> > &board, int x, int y)
    {
        int i, j;
        for (i = 0; i < 9; i++)
            if (i != x && board[i][y] == board[x][y])
                return false;
        for (j = 0; j < 9; j++)
            if (j != y && board[x][j] == board[x][y])
                return false;
        for (i = 3 * (x / 3); i < 3 * (x / 3 + 1); i++)
            for (j = 3 * (y / 3); j < 3 * (y / 3 + 1); j++)
                if (i != x && j != y && board[i][j] == board[x][y])
                    return false;
        return true;
    }
    bool solveSudoku(vector<vector<char> > &board)
    {
        for (int i = 0; i < 9; ++i)
            for (int j = 0; j < 9; ++j)
            {
                if ('.' == board[i][j])
                {
                    for (int k = 1; k <= 9; ++k)
                    {
                        board[i][j] = '0' + k;
                        if (isValid(board, i, j) && solveSudoku(board))
                            return true;
                        board[i][j] = '.';
                    }
                    return false;
                }
            }
        return true;
    }
};

解題心得

DFS常常和貪心演算法一起使用,它適合資料和計算量不太大的情況,針對每種可能進行嘗試、判斷、計算,找出最優解即可。但是,當資料量較大時,DFS可能產生計算量極大的情況,這種情況會大大降低演算法效率,因此,要特別謹慎使用!