每日一题-数组 #leetcode36

158 阅读2分钟

一、题目描述

二、题目思路

  1. 对于行、列、块,分别预设九个哈希表,键值对<出现的数字,数字出现的总次数>,遍历所有行列,对每一行(列、块同理),键的个数如果小于值的总和,代表同一个数字出现了不止一次,则判定为false。

三、提交代码

import java.util.Collection;
class Solution {
    public boolean isValidSudoku(char[][] board) {
        for(int i=0;i<9;i++){
            HashMap<Integer,Integer> maprow = new HashMap<>();
            HashMap<Integer,Integer> mapcolumn = new HashMap<>();
            HashMap<Integer,Integer> mapblock = new HashMap<>();
            for(int j =0;j<9;j++){
                int rowCurrent = (int)board[i][j] -(int)'0';
                int columnCurrent = (int)board[j][i] -(int)'0';
                int blockCurrent = (int)board[3*(i/3)+j/3][3*(i%3)+j%3] -(int)'0';
                if(rowCurrent>0){
                    maprow.put(rowCurrent,maprow.getOrDefault(rowCurrent,0)+1);
                }
                if(columnCurrent>0){
                    mapcolumn.put(columnCurrent,mapcolumn.getOrDefault(columnCurrent,0)+1);
                }
                if(blockCurrent>0){
                    mapblock.put(blockCurrent,mapblock.getOrDefault(blockCurrent,0)+1);
                }
            }
            if(maprow.keySet().size()<sum(maprow.values())||mapcolumn.keySet().size()<sum(mapcolumn.values())||mapblock.keySet().size()<sum(mapblock.values())){
                return false;
            }
        }
        return true;
    }
    public int sum(Collection<Integer> collection){
        int result =0;
        for(int i:collection){
            result+=i;
        }
        return result;
    }
}

四、存在问题

  1. 每次执行外圈循环,都需要初始化三个哈希表,对不同的行、列、块进行判断求解
  2. 需要`` import java.util.Collection
  3. 判断条件冗杂

五、优解代码

class Solution {
    public boolean isValidSudoku(char[][] board) {
        for(int i =0;i<9;i++){
            int row =0;
            int column =0;
            int block =0;
            for(int j =0;j<9;j++){
                int rowCurrent = (int)board[i][j] - (int)'0';
                int columnCurrent = (int)board[j][i] - (int)'0';
                int blockCurrent = (int)board[3*(i/3)+j/3][3*(i%3)+j%3] - (int)'0';
                
                if(rowCurrent > 0){
                    row = sodokuer(rowCurrent,row);
                }
                if(columnCurrent > 0){
                    column = sodokuer(columnCurrent,column);
                }
                if(blockCurrent > 0){
                    block = sodokuer(blockCurrent,block);
                }
                if(row ==-1||column ==-1||block ==-1){
                    return false;
                }
            }
        }
        return true;
    }
    public int sodokuer(int n,int value){
        return ((value>>n) & 1) ==1?-1:value ^(1<<n);
    }
}

六、优解思路

  1. 使用一个长度大于9的二进制数字,存储1-9出现的情况,为1,代表该数字已出现,反之为0。
  2. 将 存储值value右移n(当前遍历到的数字)位,和1做与运算,即 步骤1 的具体实现,为什么是value右移n位,而不是1左移n位?(意义相同),但因为value右移n位和1 做与运算,若重复出现,结果正好为1,方便用数字1判断
  3. 如果n已然出现过,则结果返回-1,继而返回false,程序完成
  4. 如果n未出现,则需要将n存储在存储值的对应位上,该想法可以用

原存储值与 1左移n位 做 异或运算实现

  1. 内圈for循环开始前,首先重置存储值,且对于 块 的判断:

3*(i/3)+j/3 代表第几个块

3*(i%3)+j%3 代表该块第几个元素