1. 程式人生 > >LeetCode演算法題36:有效的數獨解析

LeetCode演算法題36:有效的數獨解析

判斷一個 9x9 的數獨是否有效。只需要根據以下規則,驗證已經填入的數字是否有效即可。

  1. 數字 1-9 在每一行只能出現一次。
  2. 數字 1-9 在每一列只能出現一次。
  3. 數字 1-9 在每一個以粗實線分隔的 3x3 宮內只能出現一次。
    在這裡插入圖片描述
    上圖是一個部分填充的有效的數獨。

數獨部分空格內已填入了數字,空白格用 ‘.’ 表示。
示例 1:

輸入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: true

示例 2:

輸入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
輸出: false
解釋: 除了第一行的第一個數字從 5 改為 8 以外,空格內其他數字均與 示例1 相同。
     但由於位於左上角的 3x3 宮內有兩個 8 存在, 因此這個數獨是無效的。

說明:

  • 一個有效的數獨(部分已被填充)不一定是可解的。
  • 只需要根據以上規則,驗證已經填入的數字是否有效即可。
  • 給定數獨序列只包含數字 1-9 和字元 ‘.’ 。
  • 給定數獨永遠是 9x9 形式的。

這個題就按標記檢視行、列、3*3單元格是否數字重複即可,遍歷整個表時遇到數字將對應標誌陣列的位置置為true,如果下次發現位置已經為true說明重複,返回false。行列的標誌很好置位,單元格的陣列置位可以這樣:一共九個單元格,其座標與陣列對應位置為

(0,0)(0,1)(0,2)			(0,3)(0,4)(0,5)			(0,6)(0,7)(0,8)
(1,0)(1,1)(1,2)-->第0行	(1,3)(1,4)(1,5)-->第1行	(1,6)(1,7)(1,8)-->第2行
(2,0)(2,1)(2,2)			(2,3)(2,4)(2,5)			(2,6)(2,7)(2,8)
(3,0)(3,1)(3,2)			(3,3)(3,4)(3,5)			(3,6)(3,7)(3,8)
(4,0)(4,1)(4,2)-->第3行	(4,3)(4,4)(4,5)-->第4行	(4,6)(4,7)(4,8)-->第5行
(5,0)(5,1)(5,2)			(5,3)(5,4)(5,5)			(5,6)(5,7)(5,8)
(6,0)(6,1)(6,2)			(6,3)(6,4)(6,5)			(6,6)(6,7)(6,8)
(7,0)(7,1)(7,2)-->第8行	(7,3)(7,4)(7,5)-->第7行	(7,6)(7,7)(7,8)-->第8行
(8,0)(8,1)(8,2)			(8,3)(8,4)(8,5)			(8,6)(8,7)(8,8)

所以其對應關係可以描述為3*(i/3)+(j/3)。

C++原始碼:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int m = board.size();
        int n = board[0].size();
        if (m!=9 || n!=9) return false;
        vector<vector<bool>> row(m, vector<bool>(n, false));
        vector<vector<bool>> col(m, vector<bool>(n, false));
        vector<vector<bool>> cell(m, vector<bool>(n, false));
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                int t = board[i][j];
                if(t>='1' && t<='9')
                {
                    int k = t - '1';
                    if(row[i][k] || col[k][j] || cell[3*(i/3)+j/3][k])
                        return false;
                    row[i][k] = true;
                    col[k][j] = true;
                    cell[3*(i/3)+j/3][k] = true;
                }
            }
        }
        return true;
    }
};

python3原始碼:

class Solution:
    def isValidSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: bool
        """
        m = len(board)
        n = len(board[0])
        if m!=9 or n!=9:
            return False
        row = [[False for col in range(n)] for row in range(m)]
        col = [[False for col in range(n)] for row in range(m)]
        cell = [[False for col in range(n)] for row in range(m)]
        for i in range(m):
            for j in range(n):
                t = ord(board[i][j])
                if t>=ord('1') and t<=ord('9'):
                    k = t - ord('1')
                    if row[i][k] or col[k][j] or cell[3*(i//3)+(j//3)][k]:
                        return False
                    row[i][k] = True
                    col[k][j] = True
                    cell[3*(i//3)+(j//3)][k] = True
        return True

這裡要注意的是python中list初始化的時候的程式碼,這種初始化是比較推薦的,如果使用[[false]*n]*m這種方式只是淺複製,會造成只要修改一個那麼每一行都會修改的問題。所以還是採用推薦的方法去初始化列表。