题目描述:请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
注意:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
空白格用 '.' 表示。
输入: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
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
提示:
board.length == 9
board[i].length == 9
board[i][j] 是一位数字(1-9)或者 '.'
解决思路:Map集合:
1、由于board中的整数限定在1到9的范围内,因此可以分别建立哈希表来存储任一个数在相应维度上是否出现过。
维度有3个:所在的行,所在的列,所在的box,注意box的下标也是从左往右、从上往下的。
2、遍历到每个数的时候,例如boar[i][j],我们判断其是否满足三个条件:
在第 i 个行中是否出现过;
在第 j 个列中是否出现过;
在第 j/3 + (i/3)*3个box中是否出现过;(其中共有9个box),
下面解释给定i和j,如何判定board[i][j]在第几个box, 为什么是j/3 + (i/3)*3?
每个数属于哪个box就只取决于纵坐标,纵坐标为0/1/2的都属于box[0],纵坐标为3/4/5的都属于box[1],纵坐标为6/7/8的都属于box[2],也就是j/3.
而对于9x9的矩阵,我们光根据j/3得到0/1/2还是不够的,可能加上一个3的倍数,例如加0x3,表示本行的box,加1x3,表示在下一行的box,加2x3,
表示在下两行的box, 这里的0/1/2怎么来的?和j/3差不多同理,也就是i/3。经过上述分析可以知道[i,j]所在的box为 j/3 + i/3*3;
注意: 也许有人会问这里的i/3 * 3不是等于i本身吗?这里你要按照计算机的思维去进行计算,由于 / 和 * 的优先级是等价的,所以先计算/,
计算机在计算i/3是会出现精度缺失情况即只保留整数,然后再进行*运算。
解析参考
链接:https://leetcode-cn.com/problems/valid-sudoku/solution/36-jiu-an-zhao-cong-zuo-wang-you-cong-shang-wang-x/
链接:https://leetcode-cn.com/problems/valid-sudoku/solution/gong-shui-san-xie-yi-ti-san-jie-ha-xi-bi-ssxp/
代码实现:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class IsValidSudoku {
public static void main(String[] args) {
}
public static boolean isValidSudoku1(char[][] board) {
Map<Integer, Set<Integer>> row = new HashMap<>();
Map<Integer, Set<Integer>> column = new HashMap<>();
Map<Integer, Set<Integer>> area = new HashMap<>();
for(int i = 0; i < 9; i++){
row.put(i, new HashSet<>());
column.put(i, new HashSet<>());
area.put(i, new HashSet<>());
}
for (int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++){
char ch = board[i][j];
if(ch == '.') continue;
int num = ch - '0';
int index = i / 3 * 3 + j / 3;
if(row.get(i).contains(num) || column.get(j).contains(num) || area.get(index).contains(num)) return false;
row.get(i).add(num);
column.get(j).add(num);
area.get(index).add(num);
}
}
return true;
}
public static boolean isValidSudoku2(char[][] board) {
Map<Integer, Set<Character>> row = new HashMap<>();
Map<Integer, Set<Character>> column = new HashMap<>();
Map<Integer, Set<Character>> area = new HashMap<>();
for (int i = 0; i < board.length; i++) {
row.put(i, new HashSet<>());
column.put(i, new HashSet<>());
area.put(i, new HashSet<>());
}
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
char ch = board[i][j];
if (ch == '.') continue;
int index = j/3 + i / 3 * 3;
if(row.get(i).contains(ch) || column.get(j).contains(ch) || area.get(index).contains(ch)) return false;
row.get(i).add(ch);
column.get(j).add(ch);
area.get(index).add(ch);
}
}
return true;
}
收获: 1、本题采用了最本质的方法,按照题目的要求行,列和对应的area不能有重复的,然后就定义了9个行集合,9个列集合和9个area集合进行判断,虽然时间复杂度和空间复杂度比较高但是可以解决具体问题 。 2、本题如果使用集合,那么要求用户必须对集合特别的熟悉,特别是集合的嵌套应用 。 3、本题最难的地方就是找到[i,j]对应的box区域,要学会分析问题的方法是最重要的 。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-sudoku
|