【数学】100332. 包含所有 1 的最小矩形面积 II

2024-06-23 22:20

本文主要是介绍【数学】100332. 包含所有 1 的最小矩形面积 II,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文涉及知识点

数学

LeetCode100332. 包含所有 1 的最小矩形面积 II

给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形,并且满足 grid 中所有的 1 都在这些矩形的内部。
返回这些矩形面积之和的 最小 可能值。
注意,这些矩形可以相接。
示例 1:
输入: grid = [[1,0,1],[1,1,1]]
在这里插入图片描述

输出: 5
解释:
位于 (0, 0) 和 (1, 0) 的 1 被一个面积为 2 的矩形覆盖。
位于 (0, 2) 和 (1, 2) 的 1 被一个面积为 2 的矩形覆盖。
位于 (1, 1) 的 1 被一个面积为 1 的矩形覆盖。
示例 2:

输入: grid = [[1,0,1,0],[0,1,0,1]]
输出: 5
在这里插入图片描述

解释:
位于 (0, 0) 和 (0, 2) 的 1 被一个面积为 3 的矩形覆盖。
位于 (1, 1) 的 1 被一个面积为 1 的矩形覆盖。
位于 (1, 3) 的 1 被一个面积为 1 的矩形覆盖。

提示:
1 <= grid.length, grid[i].length <= 30
grid[i][j] 是 0 或 1。
输入保证 grid 中至少有三个 1 。

数学

我们假设某个最优解,包括左上1 的为rect1,包括右下1的矩形为rect2,另外一个矩形为rect3。我们将整个网格水平、竖直划分成3$\times$3 共9块。
第一块是:左上角是(0,0),右下角是rect1的右下角。
第二块是:左上角是rect2的左上角,右下角是网格右下角。
rect3可能站4块,也可能占3块,也可能占2块,也可能占一块。占4块包括所有占2块,占2块包括所有占1块。
下图的红色并是各种可能。
在这里插入图片描述
我们将其转化为网格的大矩形中寻找包括所有1的最小矩形。大矩形分四种情况:
在这里插入图片描述
四种情况:
一,三竖。
二,三横。
三,一竖二横。
四,一横二竖。
rect2 四种情况全部是3格,rect1 前两种情况是三格,后两种情况是二格。
遗漏了两种情况
在这里插入图片描述
借用别人的总结:
在这里插入图片描述

预处理

各矩形包括全部1的最小矩形的面积,如果不包括1,返回1000。

旧代码

需要枚举4个坐标,非常容易出错。代码通过不了,只能通过部分样例。继续调试时间成本太高。

class Solution {
public:int minimumSum(vector<vector<int>>& grid) {m_r = grid.size();m_c = grid[0].size();memset(m_area, 1, sizeof(m_area));for (int r1 = 0; r1 < m_r; r1++) {for (int c1 = 0; c1 < m_c; c1++) {for (int r2 = r1; r2 < m_r; r2++) {for (int c2 = c1; c2 < m_c; c2++) {Init(grid, r1, r2, c1, c2);}}}}for (int r1 = 0; r1 < m_r; r1++) {for (int c1 = 0; c1 < m_c; c1++) {if (0 == grid[r1][c1]) { continue; }for (int r2 = r1 + 1; r2 < m_r; r2++) {for (int c2 = 0; c2 < m_c; c2++) {Do(r1, r2, c1, c2);}}for (int c2 = c1 + 1; c2 < m_c; c2++) {for (int r2 = 0; r2 < m_r; r2++) {Do(r1, r2, c1, c2);}}}}return m_ans;}void Do( int r1, int r2, int c1, int c2) {//三横m_ans = min(m_ans, Area(0,r1,0,m_c - 1) + Area(r1 + 1,r2 - 1,0,m_c - 1) + Area(r2,m_r - 1,0,m_c - 1));//三竖m_ans = min(m_ans, Area(0,m_r - 1,0,c1) + Area(0, m_r - 1, c1 + 1,c2 - 1) + Area(0, m_r - 1, c2,m_c - 1));//一长度2的横,二长度3的竖m_ans = min(m_ans, Area(0,r1,0,c2 - 1) + Area(r1 + 1,c2 - 1,0,c2 - 1) + Area(0,m_r - 1,c2,m_c - 1));//一长度为2的竖,二长度为3横m_ans = min(m_ans, Area(0,r2 - 1,0,c1) + Area(0,r2 - 1,c1 + 1,m_c - 1) + Area(r2,m_r - 1,0,m_c - 1));//一长度3的横,二长度2的竖m_ans = min(m_ans, Area(0, r1, 0, m_c - 1) + Area(r1 + 1, c2 - 1, 0, c2 - 1) + Area(r1+1, m_r - 1, c2, m_c - 1));//一长度为3的竖,二长度为2横m_ans = min(m_ans, Area(0, m_r - 1, 0, c1) + Area(0, r2 - 1, c1 + 1, m_c - 1) + Area(r2, m_r - 1, c1+1, m_c - 1));}int Area(int r1, int r2, int c1, int c2) {if ((r1 < 0) || (r1 >= m_r)) { return m_iNotMay; }if ((r2 < 0) || (r2 >= m_r)) { return m_iNotMay; }if ((c1 < 0) || (c2 >= m_c)) { return m_iNotMay; }if ((c2 < 0) || (c2 >= m_c)) { return m_iNotMay; }return m_area[r1][r2][c1][c2];}void Init(const vector<vector<int>>& grid,int r1,int r2,int c1,int c2) {int right = -1, bottom = -1, left = 2000, top = 2000;for (int r = r1; r <= r2; r++) {for (int c = c1; c <=c2; c++) {if (grid[r][c]) {right = max(right, c);bottom = max(bottom, r);left = min(left, c);top = min(top, r);}}}m_area[r1][r2][c1][c2] = (right - left + 1) * (bottom - top + 1);}const int m_iNotMay = 1000'000;int m_area[30][30][30][30];int m_r, m_c;int m_ans = 1000'000;
};

新代码

六种情况,只需要枚举两个变量。如果用预处理,时间复杂度O(nm)或O(nn)或O(mm)。
不用预处理时间复杂度:O(nmnn)也能过,故不用预处理。

class Solution {
public:int minimumSum(vector<vector<int>>& grid) {m_r = grid.size();m_c = grid[0].size();auto Area =[&]( int r1, int r2, int c1, int c2) {int right = -1, bottom = -1, left = 2000, top = 2000;for (int r = r1; r <= r2; r++) {for (int c = c1; c <= c2; c++) {if (grid[r][c]) {right = max(right, c);bottom = max(bottom, r);left = min(left, c);top = min(top, r);}}}return (right - left + 1) * (bottom - top + 1);};{//三横for (int r1 = 0; r1 < m_r; r1++) {for (int r2 = r1 + 2; r2 < m_r; r2++) {m_ans = min(m_ans, Area(0,r1,0,m_c-1)+Area(r1+1,r2-1,0,m_c-1) + Area(r2,m_r-1,0,m_c-1));}}}{//三竖for (int c1 = 0; c1 < m_c; c1++) {for (int c2 = c1 + 2; c2 < m_c; c2++) {m_ans = min(m_ans, Area(0, m_r-1, 0,c1) + Area(0, m_r - 1, c1+1,c2-1) + Area(0, m_r - 1, c2,m_c-1));}}}for (int r = 0; r + 1 < m_r; r++) {for (int c = 0; c + 1 < m_c; c++) {//上一下二m_ans = min(m_ans, Area(0, r, 0, m_c - 1) + Area(r + 1,m_r - 1, 0, c) + Area(r + 1, m_r - 1, c+1, m_c - 1));//上二下一m_ans = min(m_ans, Area(0, r, 0, c) + Area(0, r, c+1, m_c-1) + Area(r + 1, m_r - 1, 0, m_c - 1));//左一右二m_ans = min(m_ans, Area(0, m_r - 1, 0, c) + Area(0, r, c + 1, m_c - 1) + Area(r+1, m_r - 1, c + 1, m_c - 1));//左二右一m_ans = min(m_ans, Area(0, r, 0, c) + Area(r+1,m_r-1, 0, c) + Area(0, m_r - 1, c + 1, m_c - 1));}}	return m_ans;}	const int m_iNotMay = 1000'000;int m_r, m_c;int m_ans = 1000'000;
};

代码

template<class T1, class T2>
void AssertEx(const T1& t1, const T2& t2)
{Assert::AreEqual(t1, t2);
}template<class T>
void AssertEx(const vector<T>& v1, const vector<T>& v2)
{Assert::AreEqual(v1.size(), v2.size());for (int i = 0; i < v1.size(); i++){Assert::AreEqual(v1[i], v2[i]);}
}template<class T>
void AssertV2(vector<vector<T>> vv1, vector<vector<T>> vv2)
{sort(vv1.begin(), vv1.end());sort(vv2.begin(), vv2.end());Assert::AreEqual(vv1.size(), vv2.size());for (int i = 0; i < vv1.size(); i++){AssertEx(vv1[i], vv2[i]);}
}namespace UnitTest
{vector<vector<int>> grid;TEST_CLASS(UnitTest){public:TEST_METHOD(TestMethod00){grid = { {1,0,1},{1,1,1} };auto res = Solution().minimumSum(grid);AssertEx(5, res);}TEST_METHOD(TestMethod01){grid = { {1,0,1,0},{0,1,0,1} };auto res = Solution().minimumSum(grid);AssertEx(5, res);}TEST_METHOD(TestMethod02){grid = { {0,1},{1,1} };auto res = Solution().minimumSum(grid);AssertEx(3, res);}TEST_METHOD(TestMethod03){grid = { {0,0,0},{0,1,0},{0,1,1},{0,0,0} };auto res = Solution().minimumSum(grid);AssertEx(3, res);}};
}

扩展阅读

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关推荐

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

这篇关于【数学】100332. 包含所有 1 的最小矩形面积 II的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1088436

相关文章

通过高德api查询所有店铺地址信息

通过高德api查询所有店铺地址电话信息 需求:通过高德api查询所有店铺地址信息需求分析具体实现1、申请高德appkey2、下载types city 字典值3、具体代码调用 需求:通过高德api查询所有店铺地址信息 需求分析 查询现有高德api发现现有接口关键字搜索API服务地址: https://developer.amap.com/api/webservice/gui

vue3项目将所有访问后端springboot的接口统一管理带跨域

vue3项目将所有访问后端springboot的接口统一管理带跨域 一、前言1.安装Axios2.创建Axios实例3.创建API服务文件4.在组件中使用API服务 二、跨域三、总结 一、前言 在Vue 3项目中,统一管理所有访问后端Spring Boot接口的最佳实践是创建一个专门的API服务层。这可以让你的代码更加模块化、可维护和集中管理。你可以使用Axios库作为HTT

LeetCode--155 最小栈

题目 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。push(x) -- 将元素 x 推入栈中。pop() -- 删除栈顶的元素。top() -- 获取栈顶元素。getMin() -- 检索栈中的最小元素。 示例 MinStack minStack = new MinStack();minStack.push(-2);minStack.push

Linux中拷贝 cp命令中拷贝所有的写法详解

This text from: http://www.jb51.net/article/101641.htm 一、预备  cp就是拷贝,最简单的使用方式就是: cp oldfile newfile 但这样只能拷贝文件,不能拷贝目录,所以通常用: cp -r old/ new/ 那就会把old目录整个拷贝到new目录下。注意,不是把old目录里面的文件拷贝到new目录,

图形编辑器基于Paper.js教程03:认识Paper.js中的所有类

先来认一下Paper的资源对象,小弟有哪些,有个整体的认识。认个脸。 在Paper.js的 官方文档中类大致有如下这些: 基类: ProjectViewItemPointToolSizeSegmentRectangleCurveCurveLocationMatrixColorStyleTweenToolEventGradientGradientStopEvent 二级或三级类 继承Ite

OSG数学基础:坐标系变换

三维实体对象需要经过一系列的坐标变换才能正确、真实地显示在屏幕上。在一个场景中,当读者对场景中的物体进行各种变换及相关操作时,坐标系变换是非常频繁的。坐标系变换通常包括:世界坐标系-物体坐标系变换、物体坐标系-世界坐标系变换和世界坐标系-屏幕坐标系变换(一个二维平面坐标系,即显示器平面,是非常标准的笛卡尔坐标系的第一象限区域)。 世界坐标系-物体坐标系变换 它描述的问题主要是关于物体本身的

OSG数学基础:坐标系统

坐标系是一个精确定位对象位置的框架,所有的图形变换都是基于一定的坐标系进行的。三维坐标系总体上可以分为两大类:左手坐标系和右手坐标系。常用的坐标系:世界坐标系、物体坐标系和摄像机坐标系。 世界坐标系 世界坐标系是一个特殊的坐标系,它建立了描述其他坐标系所需要的参考框架。从另一方面说,能够用世界坐标系来描述其他坐标系的位置,而不能用更大的、外部的坐标系来描述世界坐标系。世界坐标系也被广泛地

代码随想录算法训练营第三十九天|62.不同路径 63. 不同路径 II 343.整数拆分 96.不同的二叉搜索树

LeetCode 62.不同路径 题目链接:62.不同路径 踩坑:二维的vector数组需要初始化,否则会报错访问空指针 思路: 确定动态数组的含义:dp[i][j]:到达(i,j)有多少条路经递推公式:dp[i][j] = dp[i-1][j] + dp[i][j-1]初始化动态数组:dp[0][0] = 1遍历顺序:从左到右,从上到下 代码: class Solution {pu

Ural 1277 cops ans thieves (最小割模型)

题目地址 :http://acm.timus.ru/problem.aspx?space=1&num=1277 这里我们要拆点。把一个点拆成i,i' 。如何 i,j有边 ,在建边(i,j',inf),(j,i',inf)。 然后每个点点边(i',i,R[i])。这样建边以后,若要阻止 s到f的路径,那么必须破败一些边,那么我们为了是的边权最小,必须破坏边权小于inf的边,对应的就是图中拆

leetcode刷题(39)——反转链表 II

这道题可以说是非常难的,2中解法,迭代和递归,递归更加难想出来 解法1:迭代链接反转 算法 在看具体算法之前,有必要先弄清楚链接反转的原理以及需要哪些指针。举例而言,有一个三个不同结点组成的链表 A → B → C,需要反转结点中的链接成为 A ← B ← C。 假设我们有两个指针,一个指向结点 A,一个指向结点 B。 分别记为 prev 和 cur。则可以用这两个指针简单地实现 A 和 B