2732. 找到矩阵中的好子集

题目

给你一个下标从 0 开始大小为 m x n 的二进制矩阵 grid

从原矩阵中选出若干行构成一个行的非空子集,如果子集中任何一列的和至多为子集大小的一半,那么我们称这个子集是好子集。

更正式的,如果选出来的行子集大小(即行的数量)为 k,那么每一列的和至多为 floor(k / 2)

请你返回一个整数数组,它包含好子集的行下标,请你将其升序返回。

如果有多个好子集,你可以返回任意一个。如果没有好子集,请你返回一个空数组。

一个矩阵 grid 的行子集,是删除 grid 中某些(也可能不删除)行后,剩余行构成的元素集合。

示例 1:

输入:grid = [[0,1,1,0],[0,0,0,1],[1,1,1,1]]
输出:[0,1]
解释:我们可以选择第 0 和第 1 行构成一个好子集。
选出来的子集大小为 2 。
- 第 0 列的和为 0 + 0 = 0 ,小于等于子集大小的一半。
- 第 1 列的和为 1 + 0 = 1 ,小于等于子集大小的一半。
- 第 2 列的和为 1 + 0 = 1 ,小于等于子集大小的一半。
- 第 3 列的和为 0 + 1 = 1 ,小于等于子集大小的一半。

示例 2:

输入:grid = [[0]]
输出:[0]
解释:我们可以选择第 0 行构成一个好子集。
选出来的子集大小为 1 。
- 第 0 列的和为 0 ,小于等于子集大小的一半。

示例 3:

输入:grid = [[1,1,1],[1,1,1]]
输出:[]
解释:没有办法得到一个好子集。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m <= 10^4
  • 1 <= n <= 5
  • grid[i][j] 要么是 0 ,要么是 1

代码

完整代码

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* goodSubsetofBinaryMatrix(int** grid, int gridSize, int* gridColSize, int* returnSize){
    int m = gridSize; 
    int n = *gridColSize; 
    int* res = (int*)calloc(2, sizeof(int)); 
    *returnSize = 0; 

    if(m == 1) 
    {
        *returnSize = 1; 
        for (int i = 0; i < n; i++)
        {
            if(grid[0][i])
            {
                *returnSize = 0;
            }
        }
    }
    
    int *sum = (int*)calloc(m, sizeof(int)); 
    
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            sum[i] += grid[i][j];
        }
    }
    
    for (int i = 0; i < m; i++)
    {
        for (int j = i + 1; j < m; j++)
        {
            if(sum[i] + sum[j] <= n)
            {
                bool good = true;
                for (int k = 0; k < n; k++)
                {
                    if(grid[i][k] & grid[j][k])
                    {
                        good = false;
                        break;
                    }
                }
                if(good)
                {
                    res[0] = i;
                    res[1] = j;
                    free(sum);
                    *returnSize = 2;
                    return res;
                }
            }
        }
    }
    free(sum);
    return res;
}

思路分析

这套代码用了枚举的方法。

整体思路是通过计算每一行的元素和,遍历所有可能的行对组合,检查是否满足好子集的条件。

每一列的限制:对于一个好子集,任何一列的和不能超过子集大小的一半。换句话说,对于任何一列,如果我们选择了一个 1,则我们必须选择足够的 0 来平衡,以确保该列的和不超过子集大小的一半。

总和限制:对于一个子集大小为 k,其所有列的和的总和不能超过 floor(k / 2) * n。这意味着每个选择的 1 都必须有相应的 0 来平衡,以确保满足好子集的条件。

好子集的存在性:为了证明在一个存在 nn > 2)行好子集的集合中,一定至少存在两行可以构成好子集,我们可以通过反证法来证明这一点。
假设在一个存在 n 行(n > 2)好子集的集合中,没有任何两行可以构成好子集。
根据好子集的定义,对于一个包含 k 行的子集,任何一列的和至多为 floor(k / 2)。因此,如果选择的行数为 k,那么:

  • 如果 k 是偶数,则每列的和至多为 k / 2
  • 如果 k 是奇数,则每列的和至多为 (k - 1) / 2
    由于假设中没有任何两行可以构成好子集,这意味着对于任何两行,它们在任意一列中的和都超过 1。即对于任何两行 ij,存在至少一列 l 满足 grid[i][l] + grid[j][l] > 1
    现在考虑整个 n 行好子集:
  • 如果选择这 n 行,并且 n > 2,根据假设,没有任何两行可以构成好子集,因此在每列中,任意选择的两行都存在一列和超过 1
    这是矛盾的。因为根据好子集的定义,在 n 行的子集中,每列的和不能超过 floor(n / 2)。如果没有任何两行可以构成好子集,则意味着任意两行在某一列中的和都超过 1,这与好子集的定义矛盾。因此,在存在 nn > 2)行好子集的集合中,一定至少存在两行可以构成好子集。

就此我们证明了在一个存在 nn > 2)行好子集的集合中,一定至少存在两行可以构成好子集。
因此我们仅需寻找2行即可。

拆解分析

  1. 初始化和特殊情况处理
int* res = (int*)calloc(2, sizeof(int)); 
*returnSize = 0; 

if(m == 1) 
{
    *returnSize = 1; 
    for (int i = 0; i < n; i++)
    {
        if(grid[0][i])
        {
            *returnSize = 0;
        }
    }
}

初始化结果数组 res 和返回大小 returnSize。处理特殊情况,当只有一行时,检查该行是否满足条件。

  1. 计算每一行的和
int *sum = (int*)calloc(m, sizeof(int)); 

for (int i = 0; i < m; i++)
{
    for (int j = 0; j < n; j++)
    {
        sum[i] += grid[i][j];
    }
}

计算每一行的和并存储在数组 sum 中。

  1. 遍历所有行对组合,检查是否满足好子集条件
for (int i = 0; i < m; i++)
{
    for (int j = i + 1; j < m; j++)
    {
        if(sum[i] + sum[j] <= n)
        {
            bool good = true;
            for (int k = 0; k < n; k++)
            {
                if(grid[i][k] & grid[j][k])
                {
                    good = false;
                    break;
                }
            }
            if(good)
            {
                res[0] = i;
                res[1] = j;
                free(sum);
                *returnSize = 2;
                return res;
            }
        }
    }
}

遍历所有行对组合,检查每一列是否满足条件。如果满足,则返回该行对组合。

复杂度分析

  • 时间复杂度:最坏情况下,前m-1行全部相同且与第m行构成好子集,此时需要遍历所有情况,因此时间复杂度最坏为 O(m^2 * n)
  • 空间复杂度:使用了额外的数组存储每一行的和,空间复杂度为 O(m)

结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【语义分割】1-标注数据集-【单张图片】labelme标注json文件转mask

声明&#xff1a;我学习了b站&#xff1a;标注自己的语义分割数据集_哔哩哔哩_bilibili 并且复现了&#xff0c;记录了所思所得。 主要是说了&#xff1a; 做语义分割&#xff0c;数据集怎么用labelme标注成json文件&#xff0c;以及&#xff0c;json文件怎么转成mask 流程…

qlv格式转换成mp4格式,qlv转换成mp4格式软件工具转换器

在当今的互联网时代&#xff0c;视频格式转换已成为我们日常生活中的一项常见任务。其中&#xff0c;qlv转MP4的需求尤为突出&#xff0c;本文将详细介绍qlv转MP4的几种方法&#xff0c;帮助大家转换视频格式&#xff0c;我们一起来看下。 方法一&#xff1a; 1、使用 "小…

解决ubuntu18.04 安装vscode 报依赖库错误,以及打不开终端的问题。

其实很简单&#xff0c;ubuntu18.04太老了&#xff0c;官网最新版本的vscode对ubuntu18.04会有些依赖库的问题。 一顿查资料后发现2023.11月的1.85版本正常使用&#xff0c;于是完美解决。 下载链接 Visual Studio Code November 2023 点击这里下载。 下载完成&#xff0c;…

Verilog进行结构描述(structural modeling)(一):基本概念

目录 1.结构描述(structural modeling)的内容&#xff1a;2.实例 微信公众号获取更多FPGA相关源码&#xff1a; 1.结构描述(structural modeling)的内容&#xff1a; 用门来描述器件的功能基于基本元件和底层模块例化语句最接近实际的硬件结构主要使用元件的定义、使用声明以…

DCT-Net - 一键图片、视频转卡通动漫风格工具,本地一键整合包下载

只需要输入一张人物图像或者一段视频&#xff0c;就可以实现端到端全图卡、视频通化转换&#xff0c;生成二次元虚拟形象&#xff0c;返回卡通化后的结果图像或视频。 开发者叫menyi Fang&#xff0c;来自阿里巴巴通义实验室的的技术女大佬&#xff0c;国内大佬集成到webui&am…

基于SpringBoot的“智慧食堂”管理系统设计与实现

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootVue 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展示 首页 用户管理界面 菜品…

写一个坏越的个人天地(三)

昨天卡巴卡巴还是投出了学习代码以来的第一份简历,遇到好的岗位还是想争取下的吧,虽然我觉得大概率还是gg了。 昨天完成了首页的上半部分 下半部分我的构思是左右栏,左侧为菜单栏,右侧为业务栏,左侧调整右侧router进行切换内容 可以用来展示js css的小demo 稍微调整下ro…

PointCloudLib-滤波模块(Filtering)-使用体素网格过滤器对点云进行降采样

在本教程中,我们将学习如何缩减采样——即减少数量 点 – 使用体素化格网方法的点云数据集。 我们将要介绍的类在输入上创建一个 3D 体素网格(将体素网格视为空间中的一组微小 3D 框) 点云数据。然后,在每个体素(即 3D 框)中,所有点都存在 将用它们的质心近似(即下采样…

Linux驱动开发笔记(十一)tty子系统及其驱动

文章目录 前言一、串口驱动框架1.1 核心数据结构1.2 数据处理流程 二、驱动编写1. 设备树的修改2. 相关API函数3. 驱动框架4. 具体功能的实现4.1 出入口函数的编写4.2 读写函数 前言 之前已经讲过应用层的应用&#xff0c;接下来我们继续进行驱动的学习。其实实际上我们很少主动…

Linux显示服务器Wayland切换到X11

1、临时切换 &#xff1a; 注销当前用户账户&#xff0c;返回到登录屏幕。 在登录屏幕上&#xff0c;选择您要登录的用户账户。 在输入密码之前&#xff0c;在登录屏幕的右下角可能有一个齿轮图标&#xff0c;点击它以展开更多选项。 在选项中选择“Ubuntu on Xorg”或“Ubu…

从0开始学做质量工程师,只需6个月成为专业的质量管理者

欢迎来到优思学院的特别讲座——从零开始学质量工程师&#xff0c;只需6个月&#xff01;在这篇博客中&#xff0c;我们将分享满满的干货&#xff0c;帮助你在短时间内掌握成为质量工程师所需的知识和技能。无论你是刚踏入职场的新人&#xff0c;还是希望提升自身竞争力的在职人…

【ACM出版】第13届亚洲膜计算会议(ACMC2024)暨 2024年机器学习、模式识别与自动化工程国际学术会议(MLPRAE 2024,8月7日-9)

第13届亚洲膜计算会议&#xff08;ACMC2024&#xff09;暨2024年机器学习、模式识别与自动化工程国际学术会议(MLPRAE 2024) 将于2024年8月7日-9日在新加坡举行。它致力于为机器学习、模式识别与自动化工程领域的专家和学者之间的学术交流创造一个平台。 会议的理念是让来自世…

寄存器组(堆栈指针寄存器小解)

寄存器组&#xff08;堆栈指针寄存器小解&#xff09; 寄存器组栈是向下伸长的出入栈操作时候的SP寄存器 例子 寄存器组 主堆栈指针&#xff08;MSP&#xff09;&#xff1a;这是缺省的堆栈指针&#xff0c;它由 OS 内核、异常服务例程以及所有需要特权访问的 应用程序代码来使…

kubernetes pod 最小可部署计算单元

1 工作负载&#xff08;workloads&#xff09; 工作负载&#xff08;workload&#xff09;是在kubernetes集群中运行的应用程序。无论你的工作负载是单一服务还是多个一同工作的服务构成&#xff0c;在kubernetes中都可以使用pod来运行它。 workloads分为pod与controllers p…

Mysql中varchar类型数字排序不对踩坑记录

场景 在进行表设计时将版本号字段设计了为varchar类型&#xff0c;尽量从表设计阶段将数字类型列设计为int型。 再进行排序时如果版本号累计到了10及以上&#xff0c;那么再进行排序时则会出现问题。 比如下面执行排序时发现10被排在了第一位。 这是因为 varchar类型对数字…

数据增强 data augmentation(在PyTorch中,data_transforms通常用于数据集处理,并且经常用于数据增强)

数据增强是一种在训练深度学习模型时&#xff0c;通过对输入数据进行变换和修改的方法&#xff0c;以增加训练数据集的大小和多样性&#xff0c;从而提高模型的泛化能力和性能。 PS: PyTorch中&#xff0c;data_transforms具体使用代码可以查看这篇文章&#xff1a; pytor…

2024年全国VUE考试中心大全!

大家好&#xff0c;华为HCIA、HCIP、HCIE的笔试部分&#xff0c;都需要在VUE考试中心进行预约。但是很多同学都不知道当地VUE考试中心在哪里&#xff01; 为了解决大家的问题&#xff0c;这边整理了全国各大城市的VUE考试中心名称和详细地址。需要的小伙伴们可以来看看&#x…

Python联动Mysql

首先配置pip源(不然在安装库的时候会很慢!!!) pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/安装必要库: mysql.connector MySQL 连接器/ODBC 是 MySQL ODBC 驱动程序&#xff08;以前称为 MyODBC 驱动程序&#xff09;系列的名称&#xff0c;它使…

Nuxt3 的生命周期和钩子函数(一)

title: Nuxt3 的生命周期和钩子函数&#xff08;一&#xff09; date: 2024/6/25 updated: 2024/6/25 author: cmdragon excerpt: 摘要&#xff1a;本文是关于Nuxt3的系列文章之一&#xff0c;主要探讨Nuxt3的生命周期和钩子函数&#xff0c;引导读者深入了解其在前端开发中…