leetcode刷题 36. 有效的数独,Medium (Java)哈希表+数组+位运算

16 篇文章 0 订阅
14 篇文章 0 订阅
本文介绍了如何判断一个9x9的数独是否有效,主要涉及三种方法:哈希表、数组和位运算。通过遍历数独,利用哈希表、数组或位运算检查每个数字在行、列和3x3宫格中是否出现多次,从而确定数独的有效性。具体实现包括Java代码示例,详细解析了每种方法的思路和过程。
摘要由CSDN通过智能技术生成

1.题目描述

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

1.数字 1-9 在每一行只能出现一次。
2.数字 1-9 在每一列只能出现一次。
3.数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 ‘.’ 表示。

示例 1:

image.png

输入: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)或者 '.'

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-sudoku

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.题解

2.1 哈希表

2.1.1 思路

当数字只能出现一次时,自然而然会想到哈希。因为哈希集的特点就是不能存重复的值,然后本题就用了哈希表来存不同的行,列和框。当遍历到一个值时,就去查对应的行,列和框的哈希集,如果存在那就是重复了;不存在就将该值放进去。

  • 首先建立哈希表用来存不同的行,列和框。
  • 遍历哈希表,将9个行,列,框先放进去。
  • 之后遍历数独,跳过.,然后判断哈希集是否有该值,不存在就将该值加入;存在就返回false。
  • 如果遍历完整个数独都没有重复的,就返回true。

2.1.2 Java代码

class Solution {
    public boolean isValidSudoku(char[][] board) {
        HashMap<Integer,Set<Integer>> col = new HashMap<>(),row = new HashMap<>(),box = new HashMap<>();
        for(int i=0;i<9;i++){
            col.put(i,new HashSet<>());
            row.put(i,new HashSet<>());
            box.put(i,new HashSet<>());
        }
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                char c = board[i][j];
                if(c=='.'){
                    continue;
                }
                int number = c-'0';
                int boxn = (i/3*3)+j/3;
                if(col.get(i).contains(number)||row.get(j).contains(number)||box.get(boxn).contains(number)){
                    return false;
                }
                else{
                    col.get(i).add(number);
                    row.get(j).add(number);
                    box.get(boxn).add(number);
                }
            }
        }
        return true;
    }
}

2.2 数组

2.2.1 思路

前面讲过了用哈希表来存储,但其实可以直接用数组来存是否有该值。因为我是先写的哈希表,所以框的数组没有和官方题解一样用三维数组,直接用了二维。
row[][]中第一维表示的是哪一行,第二维表示的是该行中有哪个值,列和框以此类推。
如果第i行第n个值不为0,那么说明该行出现过该值,则可以返回false。接下来讲代码:

  • 首先新建三个二维数组用来存储
  • 然后遍历数组,通过数组判断是否出现重复,没出现过就将该值+1;出现就返回false
  • 最后如果没有重复,就返回true

2.2.2 Java代码

class Solution {
    public boolean isValidSudoku(char[][] board) {
        int [][]row = new int[9][9];
        int [][]col = new int[9][9];
        int [][]box = new int[9][9];
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                char c = board[i][j];
                if(c == '.'){
                    continue;
                }
                int n = c-'0'-1;
                int boxn = i/3*3+j/3;
                if(row[i][n]>0||col[j][n]>0||box[boxn][n]>0){
                    return false;
                }
                row[i][n]++;
                col[j][n]++;
                box[boxn][n]++;
            }
        }
        return true;
    }
}

2.3 位运算

2.3.1 思路

首先需要了解位运算,但是在这里不展开讲。就直接讲这一题的位运算。
假设出现了数字5,那么就将1<<5,也就是1向左移5位,就变成了二进制的(0000 0010 0000)
如果再出现了数字3,那也将1<<31向左移3位,变成二进制的(0000 0000 1000)
通过操作,也就是|将两个数放在一起,变成了(0000 0010 1000)。以此类推。
通过操作,能够判断&数组中的数字中是否存在board[i][j],比如board[i][j] = 5,那两者(0000 0010 1000)&(0000 0010 0000)= (0000 0000 0000)。那就返回false。
介绍完位运算就可以看代码结构:

  • 首先新建三个一维数组
  • 遍历数独,跳过.,之后将值变成位元素之后的值。
  • 通过且操作判断是否存在该值,存在就返回false,不存在就通过或操作将该值加入。
  • 遍历完数独,就返回true

2.3.2 Java代码

class Solution {
    public boolean isValidSudoku(char[][] board) {
        int[] row = new int[9];
        int[] col = new int[9];
        int[] box = new int[9];
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                char c = board[i][j];
                if(c == '.'){
                    continue;
                }
                int n = 1<<(c-'0');
                int boxn = i/3*3+j/3;
                if((row[i]&n)!=0||(col[j]&n)!=0||(box[boxn]&n)!=0){
                    return false;
                }
                row[i] |= n;
                col[j] |= n;
                box[boxn] |= n;
            }
        }
        return true;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值