
Valid Sudoku
The Sudoku board could be partially filled, where empty cells are filled with the character ‘.’.

Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.
| 提示 | 解題應用 | 
| Hash Table | Hash Map | 
Default:
| 1 2 3
 | func isValidSudoku(board [][]byte) bool { }
 | 
解答思路:
參數範例:
| 1
 | ["..4...63.",".........","5......9.","...56....","4.3.....1","...7.....","...5.....",".........","........."]
 | 
數讀有玩過的話規則應該都能理解,水平線與垂直線及九宮格間的數字填入1~9皆不可重覆,不過因為給的參數是二元陣列,所以就算是行與列兩者的處理方式也不太一樣,以水平列來說算是最為單純,以上述範例來說,水平的話就跟處理一維陣列資料差不多,只要遍歷每個元素是否重覆即可,不過垂直就沒那麼簡單了,因為以第一個垂直線來說,它需要獲得每個陣列中的第一個,這意味著你需要將全數二元陣列遍歷完才有辦法判斷,而九宮格則是要每爬完三條水平線才能處理,至於要怎麼知道這些數字重覆,你可以產生一個陣列如果不在陣列裡頭就儲存直到發現重覆,不過這邊我們用Hash Map的方式來做似乎比較明智些,如此一來就不用在去寫一個回圈來遍歷陣列的值是否重覆。
程式碼解說:
這邊我拆成了三個部分來說水平、垂直與九宮格的處理方式,水平相對單純許多,只要記錄一水平線中的每個值是否存在,不存在的話就塞入,這邊與接下來另外垂直與九宮格所儲存的方式一樣,主要是檢查map的key值,而不用在乎真正存入的值是什麼,這邊我姑且先和key的值一樣都是放該數字的值,而再每一水平線檢查完後就將水平的hash map清空,事實上只是重新指派新的空間,釋放記憶體的動作就交給golang的garbage collection
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 | var str string hori := make(map[string]string) for i, v := range board { 	for j, vv := range v { 		str = string(vv) 		if str != "." { 			_, okj := hori[str] 			if okj { 				return false 			} else { 				hori[str] = str 			} 		} 	} 	hori = make(map[string]string) }
 | 
垂直的部分就稍嫌麻煩許多,因為要記錄全部二元陣列的值才有辦法判斷,所以這邊hash map的key與value的值就是該垂直線的第n列+數字以此來區隔各列的數字,不過可能有人會問index的值是直接由j轉成字串,不就會變成ascii的轉換了嗎?確實是如此,因為golang要賦予key值一定要同型別所以就直接這樣轉,不過值是ascii這倒無所謂,因為主要是來區別各列不同就可以了
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 | var str string var index string vert := make(map[string]string) for i, v := range board { 	for j, vv := range v { 		index = string(j) 		str = string(vv) 		if str != "." { 			_, oki := vert[index+str] 			if oki { 				return false 			} else { 				vert[index+str] = index + str 			} 		} 	} }
 | 
九宮格的操作與水平、垂直線不同,要區分的是要存在哪一格的九宮格,因為總共分成上、中、下各三個共計九個,所以這邊我們就把i與j的值除以3即可,0,1,2除以3為0 3,4,5除以3為1 6,7,8除以3為2 並以此為座標來區分,如此以來便能很容易的將數字分配到這九個九宮格做判斷並儲存
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 | var str string var x string var y string nine := make(map[string]string) for i, v := range board { 	for j, vv := range v { 		str = string(vv) 		if str != "." { 			x = string(i / 3) 			y = string(j / 3) 			_, okk := nine[x+y+str] 			if okk { 				return false 			} else { 				nine[x+y+str] = x + y + str 			} 		} 	} }
 | 
完整程式碼:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 | func isValidSudoku(board [][]byte) bool { 	var str string 	var index string 	var x string 	var y string 	hori := make(map[string]string) 	vert := make(map[string]string) 	nine := make(map[string]string) 	for i, v := range board { 		for j, vv := range v { 			index = string(j) 			str = string(vv) 			if str != "." { 				_, oki := vert[index+str] 				_, okj := hori[str] 				x = string(i / 3) 				y = string(j / 3) 				_, okk := nine[x+y+str] 				if oki || okj || okk { 					return false 				} else { 					vert[index+str] = index + str 					hori[str] = str 					nine[x+y+str] = x + y + str 				} 			} 		} 		hori = make(map[string]string) 	} 	return true }
 | 
總結:
數讀的檢查分為水平、垂直與九宮格,因需判斷該數字是否重覆再加上垂直與九宮格皆需分類為第n列的數字與哪一格的九宮格,故hash map儲存為最佳儲存方式。
- 水平線: 最為單純,和處理一維陣列資料差不多
- 垂直線: 需增加第n列為條件來做儲存與判斷
- 九宮格: 將水平線的第x行與垂直線的第y列分別除以3為判別九宮格座標來儲存