有效的数独-位运算(详细解释)-只需遍历一遍数组

leetcode 第36 题 , 题目如下,所示.

在这里插入图片描述
在这里插入图片描述

分析:
  • 该题需要判断每一行,每一列,每一块是否有重复数字,最容想到的就是分别写代码去判断每一行,每一列是否有重复数字,用一个数组做存储容器,出现的数字作为数组的下标,出现为1,没有出现为0,这样在O(1)的时间内就可以知道数字是否重复,但是这样写代码比较冗余,需要遍历三遍,那能不能只遍历一遍呢?当然可以.
思路:

1 , 抛弃刚刚所想,更节省存储空间的话,我们可以用一个数字作为一个存储容器,利用数字二进制下的后九位,对应下标位置出现过变为1,没有出现保持0,以数字num为例,比如出现数字6,那么num的倒数第6位变为1,算数表达为:num | (1<<6),如果判断某一位是否为1,比如判断倒数第三位是否为1, (num>>3) & 1.

  • 这里补充一下位运算基本知识.
  • 按位或: |
    有一个为1,则结果为1.否则该位结果为0
  • 按位与: &
    必须两个均为1,结果为1,否则该位结果为0.
  • 按位异或: ^
    相同为0,不同为1.

2 , 如果想要只遍历一遍,那么我们就需要推导坐标之间的关系.

推导过程:

(1). 我们假设外层循环变量为ii,内层循环变量为jj,那么board[i][j]唯一表示第i 行,第j列的元素.
(2). 如何表示小宫内的格子?

  • 由于一共有9个小宫,每个小宫有9格,我们可以先找到每个小宫的第0个元素坐标,然后加上每个元素相对应第0个元素的偏移量就可以.

  • 如图所示,九个小宫用不同的颜色表示,每个小宫的左上角为小宫的第0个格子(深色标记)。我们设标号顺序为从左往右,从上往下。

  • 那么:第i个小宫的第0个元素就是(3*(i/3),3*(i%3)),

  • 每个小宫第j个元素相对于第0个元素的偏移量也就是(j/3,j%3)

  • 那么第i小宫第j个元素也就是(3∗(i/3)+j/3,3∗(i%3)+j%3)

在这里插入图片描述

接下来就是代码了.如下.
class Solution {
    public boolean isValidSudoku(char[][] board) {
        if(board==null||board.length==0) return false;
        for(int i=0;i<9;i++){
            int line=0,list=0,square=0;                 //初始化三个容器
            for(int j=0;j<9;j++){
                int val_line=(int)board[i][j]-48;       //获取每一行的值
                int val_list=(int)board[j][i]-48;       //每一列的值
                int val_sq=(int)board[3*(i/3)+j/3][3*(i%3)+j%3]-48;  //每一宫的值
                if(val_line>0)                           //'.'的ASCLL码是46,转换为数字小于0.
                    line=sodokuer(val_line,line);
                if(val_list>0)
                    list=sodokuer(val_list,list);
                if(val_sq>0)
                    square=sodokuer(val_sq,square);
                if(line==-1||list==-1||square==-1)
                    return false;
            }
        }
        return true;
    }
    private int sodokuer(int val, int res){
       //如果对应位上的数值为1,说明已经出现过,返回-1,否则对应位设为1
       return ((res>>val) & 1) == 1 ? -1 : res ^ (1<<val);  
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值