题目描述
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 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 形式的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/1/array/30/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析
需要判断每个元素的所在行,所在列以及所在的子数组内是否有该数了。
所以现在需要分成三部分:
- 判断当前元素所在行是否存在该元素对应的数字
- 判断当前元素所在列是否存在该元素对应的数字
- 判断当前元素所在子数组是否存在钙元素对应的数字
判断所在行:
定义一个布尔类型的二维数组,外层记录第几行,内层数组记录该行对应的数字是否存在
判断所在列:
定义一个布尔类型的二维数组,外层记录第几列,内层数组记录该列对应的数字是否存在
判断所在子数组:
定义一个布尔类型的二维数组,外层记录是第几个子数组,内层记录该子数组内对应的数字是否存在
如何定义子数组
9X9的数组,可以分成9个3*3的子数组,现在我们要将这9个子数组进行编号,以方便记录。
因为每三行三列为一个子数组,那么可以 i / 3 + j / 3;i,j分别对应横纵坐标,但是这样是不对的,可以看出第一行第二个子数组和第二行第一个记录出的编号是一样的。每行会有三个子数组,所以将行号乘以三,那么就可以相当于给第二行的子数组加三,第三行的子数组加六。
所以最后得到的算式即为:i / 3 * 3 + j / 3
之前的判断
因为题目中不存数字的元素存储的是’.’,我们在循环时遇到非数字,直接continue就可以,如果为数字,我们要将字符转成数字类型,而我们将声明 9 X 9 的二维布尔数组来存储数字是否已经出现过,所以我们字符转数字的算法即为:arr[i][j] - ‘1’:
思路分析完了,之后来给代码:
完整代码
func isValidSudoku(board [][]byte) bool {
// 思路: 判断行内和列内是否有重复,判断的方法是我们定义一个布尔数组,如果遍历到一个元素
// 并且这个元素的位置上的布尔值为false,那么说明没有出现过,不然就是出现过,可以直接返回false
// 记录行内数据是否存在
var rows [9][9]bool
// 记录列内数据否存在
var cols [9][9]bool
// 记录子数组中数据是否存在
var childArrs [9][9]bool
// 第一层为第几个子数组,第二层内记录
// 子数组运算 每三行三列为一个子数组,那么就是i / 3 + j / 3,但是有一个问题,这么算来,第二排第一个子数组和第一排第二个子数组算下来的是一样的,都是1。所以我们需要处理
// 将行*3,因为每行有三个,到下一行后会加三
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
item := board[i][j]
if item == '.' {
continue
}
item = item - '1'
index := i / 3 * 3 + j / 3
// 如果该行该数已经存在
if rows[i][item] {
return false
}
// 如果改列该数已经存在
if cols[j][item] {
return false
}
// 如果子数组中该数已经存在
if childArrs[index][item] {
return false
}
rows[i][item] = true
cols[j][item] = true
childArrs[index][item] = true
}
}
return true
}
判断数组中元素是否存在,可以使用一个例如map或者数组存放已出现过的数据,之后如果再出现该元素,就可以在我们声明的容器中得到。