【leetcode:2397. 被列覆盖的最多行数】子集枚举、二进制枚举以及Gosper’s hack

题目描述

2397. 被列覆盖的最多行数

给你一个下标从 0 开始、大小为 m x n 的二进制矩阵 matrix ;另给你一个整数 numSelect,表示你必须从 matrix 中选择的 不同 列的数量。

如果一行中所有的 1 都被你选中的列所覆盖,则认为这一行被 覆盖 了。

你需要从矩阵中选出 numSelect 个列,使集合覆盖的行数最大化。

返回一个整数,表示可以由 numSelect 列构成的集合 覆盖最大行数

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 12
  • matrix[i][j] 要么是 0 要么是 1
  • 1 <= numSelect <= n

简单枚举

对于很多算法问题,最直接的想法就是枚举,这题也可以用简单枚举解决:

  1. n列中选出numSelect个,总量是可以枚举出来的,由于n<=12,所以总量也是可控的。
    • n = 3 n = 3 n=3 n u m S e l e c t = 2 numSelect = 2 numSelect=2为例,所有可能的选择情况有 [ 0 , 1 , 1 ] [0, 1, 1] [0,1,1] [ 1 , 0 , 1 ] [1, 0, 1] [1,0,1] [ 1 , 1 , 0 ] [1, 1, 0] [1,1,0]
  2. 以上一步所有可能的选择情况,分别对比每一行,看是否能覆盖
  3. 覆盖行数最多的情况就是最终答案

简单枚举的思路简单,但实现起来却没那么简单,时间复杂度也高,光是枚举所有可能的列选择情况,就至少有 C n n u m S e l e c t = n ! n u m S e l e c t ! × ( n − n u m S e l e c t ) ! C_{n}^{numSelect} = \frac{n!}{numSelect! \times (n - numSelect)!} CnnumSelect=numSelect!×(nnumSelect)!n! 种,对于每一种枚举情况又要遍历每一行的所有元素,也就是 O ( m × n ) O(m \times n) O(m×n)

二进制枚举

在简单枚举的基础上,可以想到二进制枚举。也就是用一个数的二进制来表示列选择情况,结合位运算就可以提升复杂度。

同时将每一行对应的数字看作二进制,计算对应的数字。

输入: matrix = [[0,0,0],[1,0,1],[0,1,1],[0,0,1]], numSelect = 2为例

  1. 把每一行对应数字看作二进制,分别是000101011001,计算成数字分别是0、5、3、1。
  2. 使用二进制表示列选择,1表示选中,0表示不选中。那么所有可能的列选择有0(000)1(001)2(010)3(011)4(100)5(101)6(110)7(111)
  3. 其中 1 的个数 ≠ n u m S e l e c t 1的个数\neq numSelect 1的个数=numSelect的情况,表示选中的列数量不等于numSelect,明显不符合要求,可以直接跳过。
  4. 对于符合要求的每种列选择,也就是每一个数字(3、5、6)
    • 遍历每一行,这里是第1步中每一行计算出的数字
    • 列选择对应的数字与行对应的数字做&运算,如果结果还是列选择对应的数字,表示列选择覆盖了这一行

代码实现代码:

class Solution {
private:int num1ofInt(int n) {// 计算n的二进制表示中1的个数int res = 0;while(n > 0) {res += (n & 1);n >>= 1;}return res;}
public:int maximumRows(vector<vector<int>>& matrix, int numSelect) {int rowNum = matrix.size();int colNum = matrix[0].size();vector<int> states = vector<int>(rowNum, 0);for(int i = 0;i < rowNum;++i) {for(int j = 0;j < colNum;++j) {states[i] += (matrix[i][j] << (colNum - j - 1));}}int res = 0;int permutationNum = (1 << colNum);// 0 表示一列也不选,不满足要求for(int i = 1;i < permutationNum;++i) {if(num1ofInt(i) != numSelect) {continue;}int t = 0;for(int j = 0;j < rowNum;++j) {if((states[j] & i) == states[j]) {++t;}}res = max(res, t);}return res;}
};

其中自己实现的num1ofInt()可以用__builtin_popcount()代替,其作用是:

This function is used to count the number of set bits in an unsigned integer. In other words, it counts the number of 1’s in the binary form of a positive integer.

该函数用来统计正整数的二进制表示中1的个数

Gosper’s Hack

在上述实现中,为了筛选出不符合条件的枚举,增加if(__builtin_popcount(i) != numSelect) { continue; }的判断,有没有方法去掉该判断,只遍历符合条件的枚举呢?

这正是Gosper’s Hack的用武之地!

什么是Gosper’s Hack?简单来说就是:

Gosper’s Hack iterates through all n-bit values that have k bits set to 1, from lowest to highest.

遍历长度为n的二进制序列中1的数量为k的情况

这不就是为解决这里的问题而生的嘛!那如何实现呢?使用起来很简单,3行代码:

void GospersHack(int k, int n)
{int set = (1 << k) - 1;int limit = (1 << n);while (set < limit){// DoStuff(set);// Gosper's hack:int c = set & - set;int r = set + c;set = (((r ^ set) >> 2) / c) | r;}
}

这里的DoStuff()就是我们判断是否覆盖的地方。

所以使用Gosper’s Hack提升之后的代码如下 :

class Solution {
public:int maximumRows(vector<vector<int>>& matrix, int numSelect) {int rowNum = matrix.size();int colNum = matrix[0].size();vector<int> states = vector<int>(rowNum, 0);for(int i = 0;i < rowNum;++i) {for(int j = 0;j < colNum;++j) {states[i] += (matrix[i][j] << (colNum - j - 1));}}int res = 0;int limit = (1 << colNum);int set = (1 << numSelect) - 1;while(set < limit) {// doStuffint t = 0;for(int j = 0;j < rowNum;++j) {if((states[j] & set) == states[j]) {++t;}}res = max(res, t);// Gosper's hack:int c = set & -set;int r = set + c;set = (((r ^ set) >> 2) / c) | r;}return res;}
};

本文章只介绍了Gosper’s Hack的用途和用法,至于之中原理,可以参考哈弗大学的课件,或者博客文章。

参考

  1. https://leetcode.cn/problems/maximum-rows-covered-by-columns/
  2. https://read.seas.harvard.edu/~kohler/class/cs207-s12/lec12.html
  3. https://programmingforinsomniacs.blogspot.com/2018/03/gospers-hack-explained.html
  4. https://www.wayuekeji.com/index

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SQL】对表中的记录通过时间维度分组,统计出每组的记录条数

场景&#xff1a;一般用作数据统计&#xff0c;比如统计一个淘宝用户在年、月、日的维度上的订单数。 业务&#xff1a;一个集合&#xff0c;以时间维度来进行分组求和。 准备一张订单表order&#xff0c;有一些常规属性&#xff0c;比如创建时间&#xff0c;订单号。 DDL语句如…

【2023】java常用HTTP客户端对比以及使用(HttpClient/OkHttp/WebClient)

&#x1f4bb;目录 1、介绍2、使用2.1、添加配置2.1.1、依赖2.1.2、工具类2.1.3、实体2.1.4、Controller接口 2.2、Apache HttpClient使用2.3 、OkHttp使用2.4、WebClient使用 1、介绍 现在java使用的http客户端主要包括以下几种 而这些中使用得最频繁的主要是&#xff1a; A…

Deno 1.22 发布

目录 更新默认的类型检查模式 移除Deno.emit()Deno.formatDiagnostics()和Deno.applySourceMap() API 默认启用Deno命名空间 --no-config标识 Navigator.userAgent 更新 Deno.resolveDns() API 引入新的Response.json()静态方法 在 LSP 默认启用 Linting 对测试运行程…

资源调度(2)-----pod的亲和性和反亲和性

集群调度: schedule的调度算法。 预算策略&#xff1a;过滤出合适的节点 优先策略&#xff1a; 选择部署的节点 nodeName:硬匹配&#xff0c;不走调度策略。node01. nodeSelector&#xff1a;根据节点的标签选择&#xff0c;会走调度算法。 只要是走调度算法&#xff0c;在不满…

[VSCode] VSCode 常用快捷键

文章目录 VSCode 源代码编辑器VSCode 常用快捷键分类汇总01 编辑02 导航03 调试04 其他05 重构06 测试07 扩展08 选择09 搜索10 书签11 多光标12 代码片段13 其他 VSCode 源代码编辑器 官网&#xff1a;https://code.visualstudio.com/ 下载地址&#xff1a;https://code.visua…

【排序算法】二、希尔排序(C/C++)

「前言」文章内容是排序算法之希尔排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 希尔排序1.1 原理1.2 代码实现&#xff08;C/C&#xff09;1.3 特性总结 希尔排序 1.1…

数据结构-测试1

一、判断题 1.队列中允许插入的一端叫队头&#xff0c;允许删除的一端叫队尾&#xff08;F&#xff09; 队列中允许删除的一端叫队头&#xff08;front&#xff09;,允许插入的一端叫队尾&#xff08;rear&#xff09; 2. 完全二叉树中&#xff0c;若一个结点没有左孩子&#…

Developer Tools for Game Creator 1

插件包含: 持久世界时间管理系统 单击以生成对象或预设 游戏内调试控制台 游戏内事件控制台 控制台管理控制 命令模板脚本 游戏内屏幕截图 低分辨率和高分辨率图像 缩略图生成 移动支持 使用Game Creator Action或拖放来激活和控制组件,无需编码。 通过此资产,您可以获得: …

初识 Elasticsearch 应用知识,一文读懂 Elasticsearch 知识文集(1)

文章目录 &#x1f3c6; 初识 Elasticsearch 应用知识&#x1f50e; 初识 Elasticsearch 应用知识(1)&#x1f341;&#x1f341; 01、什么是 Elasticsearch&#xff1f;&#x1f341;&#x1f341; 02、能列出 10 个使用 Elasticsearch 作为其搜索引擎或数据库的公司吗&#x…

2023 年度合辑 | 出海大年的全球化产品洞察和服务动向

2023 年度合辑 年度关键词 出海&全球化 出海 & 全球化通信服务全面升维 出海大年&#xff0c;融云全球互联网通信云作为“全球化最佳基础设施”之一&#xff0c;发挥技术沉淀和实践积累带来的核心优势&#xff0c;结合市场变化对出海 & 全球化通信服务进行了全方位…

李沐之神经网络基础

目录 1.模型构造 1.1层和块 1.2自定义块 1.3顺序块 1.4在前向传播函数中执行代码 2.参数管理 2.1参数访问 2.2参数初始化 3.自定义层 3.1不带参数的层 3.2带参数的层 4.读写文件 4.1加载和保存张量 4.2加载和保存模型参数 1.模型构造 1.1层和块 import torch fr…

c JPEG编码,但有错误

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h> //v4l2 头文件 #include <strin…

MySQL之数据的导入、导出远程备份

目录 一. navicat的导入、导出 1.1 导入 1.2 导出 二. mysqldump命令导入、导出 2.1 导出 2.2 导入 三. LOAD DATA INFILE 命令导入、导出 3.1 设置 3.2 导出 3.3 导入 3.4 查看secure_file_priv设置 四. 远程备份 4.1 导出 4.2 导入 五. 思维导图 一. navicat的导入、导…

互联网云计算:开启未来智能生活的新篇章

互联网每天新进程&#xff0c;科技还得看啊浩说。 在互联网技术的飞速发展中&#xff0c;云计算已经成为了我们生活中不可或缺的一部分。它像一座神奇的云端宝库&#xff0c;为我们提供了无尽的计算资源和存储空间。让我们一起来探索互联网云计算的奥秘和魅力。 一、云计算&am…

Java多线程-Thread类的run方法

Java多线程-Thread类的run方法 一、背景二、研究Thread类的start()源码1、源码&#xff08;比较短&#xff0c;贴一下&#xff09;1.1 重点&#xff1a;start0(); 三、研究Thread类的run()源码1、源码&#xff08;很关键&#xff0c;必须贴&#xff09; 四、创建线程的2种方式1…

图灵机原理

图灵机原理 组成 一个两头无延伸的纸带&#xff0c;一个读写头&#xff0c;一本操作手册。 格式 纸带上只能写 0 和 1。 读写头可以在纸带上左右移动。 手册的每一页都有“一个判断”和“三个操作”&#xff1a; 一个判断&#xff1a;判断读写头当前位置的值是 0 还是 1&…

实习面试经历(微软/360/蔚来/百度/小米/元戎启行/腾讯)

从去年十一月到现在陆陆续续面试了好几家公司实习&#xff0c;做个简单的记录供大家参考吧&#xff0c;个人背景是某211大三的科班&#xff0c;之前没有实习经历 按照时间线&#xff1a; 11.8 微软Azure工程实习生 这是我第一次面试实习&#xff0c;个人觉得答的很不好。之前…

淘宝/天猫商品详情实时数据API技术实现

随着电子商务的蓬勃发展&#xff0c;对于电商平台的商家而言&#xff0c;实时获取商品数据变得至关重要。通过API接口&#xff0c;可以轻松地从电商平台获取这些数据。本文将详细介绍如何使用淘宝/天猫提供的API接口实现商品详情数据的实时获取&#xff0c;并给出具体的代码示例…

podman configure insecure certificate registry【podman 设置非安全镜像仓库】

预备条件 docker registry仓库私搭并配置证书centos 7.9 部署 harbor 镜像仓库实践harbor 部署入门指南Podman 部署私有镜像仓库 设置 $ vim /etc/hosts 192.168.23.47 registry.ghostwritten.com$ vim /etc/containers/registries.conf ... [[registry]] location "r…

【css技巧】css设置文字不能被选中

ChatGPT4.0国内站点&#xff1a;海鲸AI 在CSS中&#xff0c;如果你想让文本内容不能被用户选中&#xff0c;可以使用user-select属性。这个属性可以控制用户是否能够选择文本。以下是如何使用这个属性的例子&#xff1a; .unselectable {-webkit-user-select: none; /* Safar…