IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode 36. 有效的数独(中等、数组)day22 -> 正文阅读

[数据结构与算法]LeetCode 36. 有效的数独(中等、数组)day22

题目描述:请你判断一个 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中的整数限定在19的范围内,因此可以分别建立哈希表来存储任一个数在相应维度上是否出现过。
   维度有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<>();  // box区域

        for(int i = 0; i < 9; i++){
            row.put(i, new HashSet<>());  // 声明9个行Set集合
            column.put(i, new HashSet<>());  // 声明9个列Set集合
            area.put(i, new HashSet<>());   // 声明9个box区域Set集合
        }

        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<>();  // box区域

        for (int i = 0; i < board.length; i++) {
            row.put(i, new HashSet<>());  // 声明9个行Set集合
            column.put(i, new HashSet<>());  // 声明9个列Set集合
            area.put(i, new HashSet<>());  // 声明9个box区域Set集合
        }

        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;  // 计算[i,j]落在第几个box
                // 依次判断i行是否存在ch, j列是否存在ch, box区域是否存在ch
                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

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-06 11:13:30  更:2022-05-06 11:15:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:39:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码