2732. 找到矩阵中的好子集

news2024/11/15 13:28:17

题目

给你一个下标从 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)

结果

在这里插入图片描述

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

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

相关文章

考研数学|线代零基础,听谁的课比较合适?

线性代数是数学的一个重要分支&#xff0c;对于考研的学生来说&#xff0c;掌握好这门课程是非常关键的。由于你之前没有听过线性代数课&#xff0c;选择一个合适的课程和老师就显得尤为重要。 以下是一些建议&#xff0c;希望能帮助你找到合适的课程资源。 首先&#xff0c;…

迁移方案详解|使用YMP从异构数据库迁移到YashanDB

数据迁移简介 01典型场景与需求 在国产化浪潮下&#xff0c;数据库系统的国产化替代成为了一个日益重要的议题&#xff0c;有助于企业降低对外依赖&#xff0c;提升信息安全和自主性。 以Oracle、MySQL为代表的传统关系型数据库管理系统&#xff0c;在企业应用中占据了重要的…

食品供应链管理商城系统的设计、实现和代码

上线食品供应链管理商城系统的设计与实现是一项复杂且重要的任务&#xff0c;它不仅涉及到技术层面的具体实现&#xff0c;还包括业务流程的优化和用户体验的提升。本文将从系统设计、功能模块、技术选型以及实现步骤等方面进行详细探讨。 ### 系统设计 在设计食品供应链管理…

cad转换pdf怎么转换?介绍四个转换方法

cad转换pdf怎么转换&#xff1f;在数字化办公日益盛行的今天&#xff0c;CAD图纸的转换与处理成为许多专业人士不可或缺的技能。特别是在需要将CAD图纸转换为PDF格式时&#xff0c;一款功能强大的软件能够大大提高工作效率。今天&#xff0c;就为大家推荐四款CAD转PDF的神器&am…

Docker 安装Nginx部署网站 防火墙端口 数据卷挂载

拉取镜像 docker pull nginx#不写版本号 表示最新版本查看是否拉取成功 docker images#成功 nginx latest 605c77e624dd 2 years ago 141MB mysql 8.0 3218b38490ce 2 years ago 516MB mysql latest 3218b38490ce 2 years ago 5…

【乐吾乐2D可视化组态编辑器】水位随数据动态变化

External Player - 哔哩哔哩嵌入式外链播放器 示例&#xff1a;进度条&#xff0c;通常用来展示水位变化 乐吾乐2D可视化组态编辑器demo&#xff1a;https://2d.le5le.com/ 示例&#xff1a;乐吾乐2D可视化 (le5le.com)

项目实训-vue(十三)

项目实训-vue&#xff08;十三&#xff09; 文章目录 项目实训-vue&#xff08;十三&#xff09;1.概述2.处理按钮 1.概述 本篇博客将记录我在图片上传页面中的工作。 2.处理按钮 实现了图片的上传之后&#xff0c;还需要设置具体的上传按钮。 这段代码使用 Element UI 的 …

使用API有效率地管理Dynadot域名,为文件夹中的域名进行域名停放

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

探讨数字化背景下VSM(价值流程图)的挑战和机遇

在信息化、数字化飞速发展的今天&#xff0c;各行各业都面临着前所未有的挑战与机遇。作为源自丰田生产模式的VSM&#xff08;价值流程图&#xff09;&#xff0c;这一曾经引领制造业革命的工具&#xff0c;在数字化背景下又将如何乘风破浪&#xff0c;应对新的市场格局和技术变…

linux用户使用资源限制

linux用户使用资源限制 1. 概述2. 特殊权限&#xff08;SUID,SGID,SBIT&#xff09;3. 访问控制列表&#xff08;ACL&#xff09;4. 磁盘空间限制&#xff08;quota&#xff09;5. 进程资源限制5.1 ulimit5.2 cgroup 前言&#xff1a;linux是一个遵循POSIX的多用户、多任务、支…

车辆网络安全开发

随着智能汽车的快速发展&#xff0c;车载软件的数量和复杂性不断增加&#xff0c;同时也带来了网络安全风险。智能汽车软件开发是实现车辆智能化、信息化的重要手段。在智能汽车软件的开发过程中&#xff0c;开发人员需要遵循一定的规范和标准&#xff0c;以确保软件的质量和安…

2024最新免费版轻量级Navicat Premium Lite 下载和安装教程

2024最新免费版轻量级Navicat Premium Lite 下载和安装教程 关于猫头虎 大家好&#xff0c;我是猫头虎&#xff0c;别名猫头虎博主&#xff0c;擅长的技术领域包括云原生、前端、后端、运维和AI。我的博客主要分享技术教程、bug解决思路、开发工具教程、前沿科技资讯、产品评…

解决GPU 显存未能完全释放

一、 现象 算法同学反馈显存未能完全释放。 二、解决方法 一条命令搞定 注意&#xff1a;执行时注意不要误杀其他的python进程&#xff0c;需要确认好。 我的这条命令是将所有python进程都杀死了 ps -elf | grep python | awk {print $4} | xargs kill -s 9

挑战极限外,交易无疆界

交易&#xff0c;并非是仅限于金融行业的专属舞台&#xff01;在Eagle Trader&#xff0c;我们深信&#xff0c;无论您来自何方&#xff0c;都怀揣着独特的视角和优势&#xff0c;能在交易场上展现出别具一格的策略。 我们热烈欢迎来自各行各业的交易者&#xff0c;因为正是你…

【现代操作系统】什么是操作系统

1.前言 现代计算机系统由一个或多个处理器、主存、磁盘、打印机、键盘、鼠标、显示器、网络接口以及各种其他输入/输出设备组成。一般而言&#xff0c;现代计算机系统是一个复杂的系统。如果每位应用程序员都不得不掌握系统的所有细节&#xff0c;那就不可能再编写代码了。而且…

【工具推荐】ONLYOFFICE 桌面编辑器 8.1:引入全新功能,提升文档处理体验

ONLYOFFICE 桌面编辑器 8.1 现已发布&#xff1a;功能完善的 PDF 编辑器、幻灯片版式、改进从右至左显示、新的本地化选项等 【工具推荐】ONLYOFFICE 桌面编辑器 8.1&#xff1a;引入全新功能&#xff0c;提升文档处理体验 一、什么是ONLYOFFICE&#xff1f; ONLYOFFICE 是…

MySQL超详细安装配置教程(亲测有效)

目录 1.下载mysql 2.环境配置 3.安装mysql ​4.navicat工具下载与连接 ​5总结 1.下载mysql mysql下载--MySQL &#xff1a;&#xff1a; 下载 MySQL 社区服务器 下载的时候这里直接逃过就行 我这里的版本是最新的mysql8.0.37 下载完成之后,将压缩包进行解压 这里我建议大…

CCSK认证考试详解:内容、形式、费用及备考指南

CCSK认证考试&#xff0c;也称为CCSK考试&#xff0c;是关于云计算安全的专业认证&#xff0c;由国际云安全联盟&#xff08;Cloud Security Alliance, CSA&#xff09;推出。以下是关于CCSK认证考试的详细信息&#xff1a; 考试内容 CCSK考试内容涵盖了云安全的基础知识&…

金融科技在智能投研领域的应用与前景

随着科技的飞速发展&#xff0c;金融科技&#xff08;FinTech&#xff09;正逐步渗透到金融行业的各个细分领域&#xff0c;其中智能投研领域作为金融科技的重要应用之一&#xff0c;正展现出巨大的潜力和广阔的前景。智能投研利用大数据、人工智能&#xff08;AI&#xff09;等…

图的深度和广度优先搜索

图的遍历有深度优先搜索和广度优先搜索两种 深度优先搜索 类似于树的先根遍历&#xff0c;但图不同于树的地方在于&#xff0c;它可能存在回路/环&#xff0c;那么在进行遍历的时候&#xff0c;同一个顶点可能会被多次搜索到&#xff0c;如果一个顶点被访问过了&#xff0c;要进…