LeetCode数独问题中Bitset的巧妙用处

2023-05-16

LeetCode数独问题中Bitset的巧妙用处

36. 有效的数独

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

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

img1

上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:

输入:
[
  ["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:

输入:
[
  ["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 存在, 因此这个数独是无效的。

题解:

bitset​代表每一行每一列中对应的数字是否出现过

  • r o w s [ i ] rows [i] rows[i] 代表第 i i i行的状态,例如第 i i i行出现了 5 5 5,那么 r o w [ i ] [ 5 ] = 1 row[i][5] = 1 row[i][5]=1
  • c o w s [ i ] cows[i] cows[i] 代表第 i i i列的转状态
  • c e l l s [ i ] [ j ] cells[i][j] cells[i][j] 代表 i i i j j j列所在的块的状态

solution:

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        vector<bitset<9> > rows = vector<bitset<9> > (9, bitset<9>());
        vector<bitset<9> > cols = vector<bitset<9> > (9, bitset<9>());
        vector<vector<bitset<9> > > cells = vector<vector<bitset<9> > > (3, vector<bitset<9> >(3, bitset<9>()));

        for(int i=0; i<9; i++){
            for(int j=0; j<9; j++){
                if(board[i][j] == '.') continue;
                int x = board[i][j]-'1';
                if(rows[i][x] || cols[j][x] || cells[i/3][j/3][x]) return false;
                rows[i][x] = 1;
                cols[j][x] = 1;
                cells[i/3][j/3][x] = 1;
            }
        }
        return true;
    }
};

37. 解数独

难度困难579

编写一个程序,通过已填充的空格来解决数独问题。

一个数独的解法需遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

空白格用 '.' 表示。

img1

一个数独。

在这里插入图片描述

答案被标成红色。

题解:

  • bitset​作用同上。
  • 每一个格子就可以计算出所有不能填的数字,然后得到所有能填的数字 getPossibleStatus()​
  • 填入数字和回溯时,只需要更新存储信息
  • 每个格子在使用时,会根据存储信息重新计算能填的数字
  • getNext() 选择能填的数字最少的格子开始填,这样填错的概率最小,回溯次数也会变少
  • fillNum() 在填入和回溯时负责更新存储信息

Solution:

class Solution {
public:
    vector<bitset<9> > rows, cols;
    vector<vector<bitset<9> > > cells;

    bitset<9> getPosibleStatus(int x, int y){
        return ~(rows[x] | cols[y] | cells[x/3][y/3]);
    }

    vector<int> getNext(vector<vector<char> > &board){
        
        vector<int> ans;
        int minCnt = 0x3f;
        for(int i=0; i<board.size(); i++){
            for(int j=0; j<board[i].size(); j++){
                if(board[i][j] != '.') continue;
                auto cur = getPosibleStatus(i, j);
                int c = cur.count();
                if(c < minCnt){
                    minCnt = c;
                    ans = {i, j};
                }
            }
        }

        return ans;
    }
    void fillNum(int x, int y, int n, bool flag){
        rows[x][n] = flag ? 1 : 0;
        cols[y][n] = flag ? 1 : 0;
        cells[x/3][y/3][n] = flag ? 1 : 0;
    }

    bool helper(vector<vector<char> > &board, int cnt){
        if(cnt == 0) return true;

        auto next = getNext(board);
        auto bits = getPosibleStatus(next[0], next[1]);

        for(int i=0; i<bits.size(); i++){
            if(!bits.test(i)) continue;
            int x = next[0], y = next[1];
            fillNum(x, y, i, true);
            board[x][y] = i+'1';
            if(helper(board, cnt-1)) return true;
            board[x][y] = '.';
            fillNum(x, y, i, false);
        }

        return false;
    }
    void solveSudoku(vector<vector<char>>& board) {
        rows = vector<bitset<9> > (9, bitset<9>());
        cols = vector<bitset<9> > (9, bitset<9>());
        cells = vector<vector<bitset<9> > > (3, vector<bitset<9> >(3, bitset<9>()));


        int cnt = 0;
        for(int i=0; i<board.size(); i++){
            for(int j=0; j<board[i].size(); j++){
                cnt += (board[i][j] == '.');
                if(board[i][j] == '.') continue;
            
                int n=board[i][j] - '1';
                rows[i] |= (1<<n);
                cols[j] |= (1<<n);
                cells[i/3][j/3] |= (1<<n);
            }
        }

        helper(board, cnt);
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LeetCode数独问题中Bitset的巧妙用处 的相关文章

  • 单片机对底层寄存器的操作

    最近项目用到了国产的一款单片机 xff0c 没有例程的支持 xff0c 需要自己从头开始写底层 又感受到了自己本科刚学习51的时候的浮躁 xff0c 不懂得如何操作底层的寄存器 xff0c 只是一味的抄写别人的例程 xff0c 然后进行简单
  • PyQt5自学记录(1)——PyQt5多线程实现详解

    PyQt5自学记录 xff08 1 xff09 PyQt5中多线程实现详解 最近想用PyQt5完成图像识别的一个GUI系统 xff0c 在调用算法模型进行识别的时候 xff0c 界面会卡住没有反应 xff0c 所以想学习一下多线程解决这个问
  • 编写程序的步骤

    编写 C 语言程序的7个步骤 1 定义程序的目标 资深程序员需要养成的良好的思考习惯 在动手写程序之前 xff0c 要在脑中有清晰的思路 想要程序去做什么 1 首先自己要明确自己想做什么 xff0c 2 思考你的程序需要哪些信息 xff0c
  • 看懂英文数据手册、搭建电路

    阅读数据手册是一个工程师的必备技能 xff0c 拿到一份数据手册 xff0c 特别是英文数据手册 xff0c 如何去读 xff0c 才能更快更好的找到自己想要的东西 xff1f 坚信 xff1a 阅读英文手册 xff0c 并没有想象的那么难
  • 英语四级重点短语

    devote to 将 致力于 derive from 61 originate from 61 stem from 源自于 instant adj 立即的 速溶的 instant coffee速溶咖啡 instant noodle 方便面
  • stm32串口通信的一个小总结(从底层进行理解)

    从底层理解stm32USART串口通信 以前学串口通信踩过很多坑 xff0c 过了一段时间又有些忘了 xff0c 现在问了几个很强很强的人差不多弄懂了 xff0c 现在写一写总结 xff0c 免得以后又忘了 基本知识 xff1a 1 TDR
  • 旋翼回收火箭系列博客3——控制系统设计(PX4火箭)

    绪论 为了缩短研制周期和提高产品可靠性 xff0c 本系统采用商用开源自动驾驶仪PX4 xff0c 实现旋翼空中展开并回收的功能 PX4是全球最为成熟的开源自动驾驶仪 xff0c 可实现自动起飞 降落 执行航点等基本任务 然而此次火箭比赛要
  • 创建进程的系统调用

    Unix采用fork exec两个系统调用来完成新进程的创建 fork 创建调用该命令的进程的副本 子进程与父进程几乎处处相同 xff0c fork后两个进程执行的程序是一样的 xff0c id不一样 xff0c 相应变量就不一致 xff0
  • vscode解决git提交冲突

    我的场景 xff1a master分支在一台电脑上被修改提交到远程后 xff0c 在另一台电脑上没有拉取远程更改 xff0c 也进行了更改提交 点击vscode看到合并冲突文件为index js 点击查看冲突如下 有颜色的是冲突位置代码 x
  • LZW压缩算法(数据无损压缩)

    目录 一 LZW算法介绍 二 算法介绍 1 LZ xff37 算法的基本概念 2 LZW压缩的基本原理 3 LZW算法流程 xff1a 零 常用无损数据压缩算法 字典算法 游程编码 基于字典编码技术的LZW算法 基于哈夫曼编码原理的压缩算法
  • sftp账号创建和权限设置

    操作前需先开启telnet服务 xff0c 防止修改sshd config后 xff0c sshd服务启不了 systemctl span class token keyword start span telnet span class t
  • Python【列表】

    文章目录 1 列表的方法及注释2 其他修改列表的办法2 列表推导式3 列表的切片4 列表转换4 1 字符串转列表 xff1a 4 2 列表转字符串 list 列表 是一个可变序列 1 列表的方法及注释 列表的方法注释append x 将元素
  • FTP的port模式和pasv模式

    FTP的port模式和pasv模式 FTP具有两种模式 xff0c 分别是port模式 也叫主动模式 和pasv模式 也叫被动模式 主动模式 主动模式的FTP是指服务器主动连接客户端的数据端口 xff0c 可以理解为服务端主动给客户端传输文
  • shell for循环多个变量

    1 使用花括号 var1 var2 var3 a 61 span class token string 34 apple 34 span span class token punctuation span b 61 span class t
  • shell 基本运算符

    文章目录 1 算数运算2 关系运算符3 布尔运算符4 逻辑运算符5 字符串运算符6 文件测试运算符知识点 1 算数运算 方法一 sum1 61 96 expr 3 span class token operator 43 span 5 96
  • Dockerfile简介

    1 什么是dockerfile Dockerfile是一个包含用于组合映像的命令的文本文档 可以使用在命令行中调用任何命令 Docker通过读取Dockerfile中的指令自动生成映像 docker build命令用于从Dockerfile
  • 容器通信之跨链接通信

    前言 同一主机下搭建容器应用栈的环境 xff0c 只需要完成容器互联来实现容器间的通信即可 xff0c 这里采用docker run link选项建立容器间的互联关系 docker官方已不推荐使用docker run link来链接2个容器
  • Linux进程间通信

    1 unix域套接字 域套接字 xff1a 1 只能用于同一设备上不同进程之间的通信 xff1b 2 效率高于网络套接字 域套接字仅仅是复制数据 xff0c 并不走协议栈 xff1b 3 可靠 xff0c 全双工 xff1b 2 IP套接字
  • 什么是API

    1 什么是API API是Application Programming Interface xff08 应用程序接口 xff09 的缩写 是一些预先定义的函数 xff0c 目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力
  • FreeRTOS(二)任务基础知识

    一 前后台系统与RTOS 前后台系统 61 死循环 xff08 通常为1个 xff09 43 中断服务程序 xff08 通常为若干个 xff09 应用程序是一个无限循环 xff0c 循环中调用 API 函数完成所需的操作 xff0c 这个大

随机推荐