1 題目描述



檢查一個數獨是否合法,合法的數獨滿足以下條件:

  1. 每一行的數字都是1-9,且不重複
  2. 每一列的數字都是1-9,且不重複
  3. 每一個3x3的小格子裡的數字都是1-9,且不重複

注意:不用檢查數獨是否有解,只需要檢查數獨是否合法。

2 解法

其實思路很簡單,我們看到需要滿足的三個條件,就可以分別實現這三個條件的檢查函數,然後分別檢查即可。

但是在這之前你會發現這三個條件都有個共通點就是數字不重複,所以我們可以針對此設計一個不重複的檢查函數。
不重複

  • 透過set的特定把重複的移除,然後比較移除"."後的長度是否相等即可。
1
2
3
4
def check_unique(nums):
# 移除'.'的數組
nums = [num for num in nums if num != '.']
return len(set(nums)) == len(nums)

檢查row

1
2
3
4
5
def check_row(board):
for row in board:
if not check_unique(row):
return False
return True

檢查column

  • 檢查column比較特殊,有使用到zip的技巧
  • 使用*board它會將可迭代對象中的元素一一傳入函數
    • 例如,f(*[row1, row2, row3]) 等同於 f(row1, row2, row3)
  • 簡單來說我們需要取麼個row的第i個元素,因為zip可以把多個list的第i個元素取出來,組合成一個元素
    • zip(row1, row2, row3) 就會變成 [(row1[0], row2[0], row3[0]), (row1[1], row2[1], row3[1]), ...]
1
2
3
4
5
6
7
# zip 的使用,把多個list的第i個元素取出來,組合成一個元素
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']

zipped = zip(list1, list2)
print(list(zipped))
# 輸出:[(1, 'a'), (2, 'b'), (3, 'c')]
1
2
3
4
5
def check_column(board):
for col in zip(*board):
if not check_unique(col):
return False
return True

檢查3x3

  • 你會發現他有個規律,row裡面的資料會是[0:3], [3:6], [6:9]的檢查順序,然後以3個row為一個單位檢查,所以row的index也會是[0, 3, 6]
1
2
3
4
5
6
7
def check_square(board):
for i in range(0, 3, 6):
for j in range(0, 3, 6):
square = [board[row][col] for row in range(i, i+3) for col in range(j, j+3)]
if not check_unique(square):
return False
return True

最後就可以合併

1
2
3
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
return self.is_row_valid(board) and self.is_col_valid(board) and self.is_square_valid(board)

3 結論

這題目難,沒有高深技巧,但是我認為最難的是:

  • column 該怎麼取得?zip(*baord)很重要
  • square 該怎麼取得?使用雙層for取得[board[row][col] for row in range(i, i+3) for col in range(j, j+3)]