[LeetCode解題攻略] 36. Valid Sudoku

更新 發佈閱讀 11 分鐘

問題描述

給定一個 9x9 的數獨棋盤,請驗證這個棋盤是否有效。

數獨棋盤需滿足以下條件:

  1. 每一行只能包含數字 1-9,不能重複。
  2. 每一列只能包含數字 1-9,不能重複。
  3. 每一個 3x3 的子方格只能包含數字 1-9,不能重複。

注意:

  • 數獨棋盤中空格由 '.' 表示。
  • 不需要檢查是否可以解出這個數獨,只需要驗證數獨是否有效。


範例 1

vocus|新世代的創作平台
輸入:
board =
[["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

輸入:
board =
[["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
解釋:第一列有兩個 8,因此這個棋盤是無效的。

解法一:使用集合檢查每一行、每一列和每個子方格

思路

我們可以將數獨棋盤視為三部分來驗證:

  1. 每一行是否有重複數字。
  2. 每一列是否有重複數字。
  3. 每一個 3x3 子方格是否有重複數字。

對於每部分,我們可以使用 集合 來檢查是否有重複數字:

  • 如果某數字已經存在於集合中,則表示有重複,棋盤無效。
  • 如果某位置是 '.',則忽略。

程式碼

class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [set() for _ in range(9)]
cols = [set() for _ in range(9)]
boxes = [set() for _ in range(9)]

for i in range(9):
for j in range(9):
num = board[i][j]
if num == '.':
continue

# 檢查行
if num in rows[i]:
return False
rows[i].add(num)

# 檢查列
if num in cols[j]:
return False
cols[j].add(num)

# 檢查子方格
box_index = (i // 3) * 3 + (j // 3)
if num in boxes[box_index]:
return False
boxes[box_index].add(num)

return True

時間與空間複雜度

  • 時間複雜度:O(1)
    數獨棋盤大小固定為 9x9,因此無論如何最多遍歷 81 個格子,時間複雜度為常數。
  • 空間複雜度:O(1)
    使用了三個長度為 9 的集合來存儲行、列和子方格的數字,總空間需求固定。

解法二:壓縮空間版本

思路

我們可以用 唯一標識符 來壓縮存儲需求,僅用一個集合來記錄每個數字是否出現過。

  1. 將每個數字出現的條件轉化為字串標識,例如:
    • 數字 5 出現在第 0 行,標識為 "5 in row 0"
    • 數字 5 出現在第 1 列,標識為 "5 in col 1"
    • 數字 5 出現在子方格 (0,0),標識為 "5 in box 0-0"
  2. 將這些標識存入集合,如果發現重複標識則返回 False

程式碼

class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
seen = set()
for i in range(9):
for j in range(9):
num = board[i][j]
if num == '.':
continue

row_key = f"{num} in row {i}"
col_key = f"{num} in col {j}"
box_key = f"{num} in box {i//3}-{j//3}"

if row_key in seen or col_key in seen or box_key in seen:
return False

seen.add(row_key)
seen.add(col_key)
seen.add(box_key)

return True

時間與空間複雜度

  • 時間複雜度:O(1)
    同樣固定遍歷 81 個格子。
  • 空間複雜度:O(1)
    由於最多存儲 81 條標識(每個數字最多三條標識),空間需求仍然是固定的。

解法三:逐步檢查行、列、子方格

思路

  1. 檢查每一行:將每一行的數字存入集合,檢查是否有重複。
  2. 檢查每一列:同樣將每一列的數字存入集合,檢查是否有重複。
  3. 檢查每個子方格:對每個子方格中的數字進行檢查。

這種方法較為直觀,分開處理每部分。

程式碼

class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
def isValidSet(values):
nums = [v for v in values if v != '.']
return len(nums) == len(set(nums))

# 檢查行
for row in board:
if not isValidSet(row):
return False

# 檢查列
for col in zip(*board):
if not isValidSet(col):
return False

# 檢查子方格
for i in range(0, 9, 3):
for j in range(0, 9, 3):
box = [board[x][y] for x in range(i, i + 3) for y in range(j, j + 3)]
if not isValidSet(box):
return False

return True

時間與空間複雜度

  • 時間複雜度:O(1)
    固定遍歷 81 個格子,且每次檢查集合操作為常數時間。
  • 空間複雜度:O(1)
    每次檢查時僅臨時存儲數字,無額外存儲需求。

結論

  1. 最佳解法解法二(壓縮空間版本),僅用一個集合,實現簡潔且高效。
  2. 其他解法:對於初學者,解法一解法三 更容易理解。
  3. 此題重點在於如何高效檢查每一行、每一列與每個子方格是否符合規範,並通過集合實現唯一性檢查。
留言
avatar-img
追極光的北極熊|軟體工程師的小天地
16會員
173內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
看更多
你可能也想看
Thumbnail
見諸參與鄧伯宸口述,鄧湘庭於〈那個大霧的時代〉記述父親回憶,鄧伯宸因故遭受牽連,而案件核心的三人,在鄧伯宸記憶裡:「成立了成大共產黨,他們製作了五星徽章,印刷共產黨宣言——刻鋼板的——他們收集中共空飄的傳單,以及中國共產黨中央委員會有關文化大革命決議文的英文打字稿,另外還有手槍子彈十發。」
Thumbnail
見諸參與鄧伯宸口述,鄧湘庭於〈那個大霧的時代〉記述父親回憶,鄧伯宸因故遭受牽連,而案件核心的三人,在鄧伯宸記憶裡:「成立了成大共產黨,他們製作了五星徽章,印刷共產黨宣言——刻鋼板的——他們收集中共空飄的傳單,以及中國共產黨中央委員會有關文化大革命決議文的英文打字稿,另外還有手槍子彈十發。」
Thumbnail
題目會給我們節點總數目n、左子樹的關係陣列、右子樹的關係陣列,要求我們驗證在給定的條件下,能不能構成一顆合法的二元樹。
Thumbnail
題目會給我們節點總數目n、左子樹的關係陣列、右子樹的關係陣列,要求我們驗證在給定的條件下,能不能構成一顆合法的二元樹。
Thumbnail
當代名導基里爾.賽勒布倫尼科夫身兼電影、劇場與歌劇導演,其作品流動著強烈的反叛與詩意。在俄烏戰爭爆發後,他持續以創作回應專制體制的壓迫。《傳奇:帕拉贊諾夫的十段殘篇》致敬蘇聯電影大師帕拉贊諾夫。本文作者透過媒介本質的分析,解構賽勒布倫尼科夫如何利用影劇雙棲的特質,在荒謬世道中尋找藝術的「生存之道」。
Thumbnail
當代名導基里爾.賽勒布倫尼科夫身兼電影、劇場與歌劇導演,其作品流動著強烈的反叛與詩意。在俄烏戰爭爆發後,他持續以創作回應專制體制的壓迫。《傳奇:帕拉贊諾夫的十段殘篇》致敬蘇聯電影大師帕拉贊諾夫。本文作者透過媒介本質的分析,解構賽勒布倫尼科夫如何利用影劇雙棲的特質,在荒謬世道中尋找藝術的「生存之道」。
Thumbnail
Leetcode #101 Symmetric Tree 題目會給定一顆樹,要求我們判定這棵樹是不是左右鏡像對稱(Symmetric)。
Thumbnail
Leetcode #101 Symmetric Tree 題目會給定一顆樹,要求我們判定這棵樹是不是左右鏡像對稱(Symmetric)。
Thumbnail
題目敘述 題目會給我們一個陣列,要求我們返回 兩數之和=target所在的陣列索引值。 題目還額外保證,一定剛好有一組解。 測試範例 Example 1: Input: nums = [2,7,11,15], target = 9 Output: [0,1]
Thumbnail
題目敘述 題目會給我們一個陣列,要求我們返回 兩數之和=target所在的陣列索引值。 題目還額外保證,一定剛好有一組解。 測試範例 Example 1: Input: nums = [2,7,11,15], target = 9 Output: [0,1]
Thumbnail
本遊戲為李國賢老師所研發,已經出版專書一套四冊。若你對此遊戲或數學有興趣,請跟我聯繫:[email protected]
Thumbnail
本遊戲為李國賢老師所研發,已經出版專書一套四冊。若你對此遊戲或數學有興趣,請跟我聯繫:[email protected]
Thumbnail
給定一個9x9的輸入陣列代表數獨題目已經 部分作答 的狀態, 請驗證已經作答的部分是否為合法的Sudoku的輸入。 註: 合法的Sudoku輸入必須滿足這些規則 1~9每一直排恰好出現一次。 1~9每一橫排恰好出現一次。 1~9在3x3的小方陣裏恰好出現一次。
Thumbnail
給定一個9x9的輸入陣列代表數獨題目已經 部分作答 的狀態, 請驗證已經作答的部分是否為合法的Sudoku的輸入。 註: 合法的Sudoku輸入必須滿足這些規則 1~9每一直排恰好出現一次。 1~9每一橫排恰好出現一次。 1~9在3x3的小方陣裏恰好出現一次。
Thumbnail
給定一個整數陣列hand代表手牌點數,和參數groupSize。請問能不能每groupSize牌一組,每一組都拼出順子? 如果可以,返回True。如果無解,返回False。演算法使用最小堆積或排序。關鍵知識點:從小到大掃描每張牌,檢查能不能組成牌組長度為groupSize的順子即可。
Thumbnail
給定一個整數陣列hand代表手牌點數,和參數groupSize。請問能不能每groupSize牌一組,每一組都拼出順子? 如果可以,返回True。如果無解,返回False。演算法使用最小堆積或排序。關鍵知識點:從小到大掃描每張牌,檢查能不能組成牌組長度為groupSize的順子即可。
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News