10 有效的数独-20200321
题目
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
- 数字
1-9
在每一行只能出现一次。 - 数字
1-9
在每一列只能出现一次。 - 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。
数独部分空格内已填入了数字,空白格用 '.'
表示。
示例
输入:
[
["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
说明
- 一个有效的数独(部分已被填充)不一定是可解的。
- 只需要根据以上规则,验证已经填入的数字是否有效即可。
- 给定数独序列只包含数字
1-9
和字符'.'
。 - 给定数独永远是
9x9
形式的。
注意事项
- 数独的形式永远都是9x9。
- 空格用字符 '.'来代替了。
每个3x3的数组有5个数字,所以1-9每个数字都要出现5次。也就是说每个数字的重复次数等于5。不对!!
思路一
用四个指针i,j,k,h做。三个判断设置用和三个字典single、row和column实现。数组来存储各个3*3的元素是否存在的指示。字典用来判断每行每列的重复元素。
- 判断字典single[nums[i,j]]是否为1,同时判断字典row[nums[i,j]]的数组中是否有i,字典colum[nums[i,j]的数组中是否有j。如果有一项不成立就返回False。否则字典存入相应项,并j加一。j在range(h,h+3)。
- 判断j是否等于2,5,8。如果等于就重置字典single,h+=3,否则pass。
- i循环range(k,k+3),循环完毕就k+=3。
修改经历:
1. 在判断时,把元素当做行列的index了。(第一次提交)
- 解答错误
2. 修改过后,提交成功。(第二次提交)
- 执行用时 :48 ms, 在所有 Python3 提交中击败了92.28%的用户
- 内存消耗 :13.6 MB, 在所有 Python3 提交中击败了5.03%的用户
心得体会:
- 注意 i = j = 0 和 i, j =0, 0的区别,前者相当于两个指针指向一个地址,后者是两个指针指向两个地址。同理列表,字典等都是一样的。
- 还有 list 和 narray 的区别,前者是[i][j]取元素,后者是[i,j]取元素。
- 这个思路真的是很垃圾,其实这不是列表呢,直接取出来每行每列判断就好,难点就在怎么判断3*3的矩阵。
- 字典可以这么写
rows = [{} for i in range(9)]
最终代码展示:
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
i, j, k, h = 0, 0, 0, 0
single = {0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], 8:[], 9:[]}
row = {0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], 8:[], 9:[]}
column = {0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], 8:[], 9:[]}
for k in range(0, 9, 3):
for h in range(0, 9, 3):
for i in range(k, k+3):
for j in range(h, h+3):
if board[i][j] != '.':
item = int(board[i][j])
if 1 not in single[item] and i not in row[item] and j not in column[item]:
single[item] += [1]
row[item] += [i]
column[item] += [j]
else:
return False
else:
pass
single = {0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], 8:[], 9:[]}
return True
思路二
这次直接取出来判断。不要一个一个元素进行判断。比较难判断的就是每一小块怎么判断。找到每一块的index与循环次数的关系就好。n=[0,1,...,8],则Z形排列的小块的index为,横坐标=[3*int(n/3):3*int(n/3)+3],纵坐标=[3*int(n%3):3*int(n%3)+3]。
修改经历:
1. 写了半天,or写成and了。。。(第一次提交)
- 解答错误
2. 修改过提交成功。(第二次提交)
- 执行用时 :124 ms, 在所有 Python3 提交中击败了23.89%的用户
- 内存消耗 :13.6 MB, 在所有 Python3 提交中击败了5.03%的用户
心得体会:
- 一定要注意列表的切片与narray不同!!!A=[[1,2],[3,4]]要取出[1,3]要单独在每一个list里取相应index的值。A[:][0]与A[:][0]都是[1,2]。[x[0] for x in A]才行。
- 怎么还慢了呢?
最终代码展示:
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
for n in range(1, 10):
for k in range(0, 9):
column = [x[k] for x in board]
temp = [x[3*int(k%3):3*int(k%3)+3] for x in board[3*int(k/3):3*int(k/3)+3]]
block = []
for item in temp:
block += item
if board[k][:].count(str(n)) > 1 or column.count(str(n)) > 1 or block.count(str(n)) > 1:
return False
return True