首页 > 其他分享 >【数学】100332. 包含所有 1 的最小矩形面积 II

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

时间:2024-06-23 17:59:14浏览次数:3  
标签:r1 r2 Area int II c2 c1 矩形 100332

本文涉及知识点

数学

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++**实现。

标签:r1,r2,Area,int,II,c2,c1,矩形,100332
From: https://blog.csdn.net/he_zhidan/article/details/139901269

相关文章

  • Leetcode84 柱状图中最大的矩形
    题目描述给定n个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为1。求在该柱状图中,能够勾勒出来的矩形的最大面积解题思路思路一:暴力寻找,从每个位置出发,向左右两边扩散查找,若发现柱形比当前位置高,则宽度加一,组成长方形,代码实现如下,但是提交之后......
  • 力扣-122. 买卖股票的最佳时机 II
    1.题目题目地址(122.买卖股票的最佳时机II-力扣(LeetCode))https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/题目描述给你一个整数数组prices,其中 prices[i]表示某支股票第i天的价格。在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最......
  • windows服务器上用nginx转发到iis中的网站
    windows服务器上用nginx转发到iis中的网站2024年6月23日测试通过前提:华为云1核心2G内存1M带宽服务器¥40/年,还没有备案,80端口用不了,在安全组里把81端口打开了,同时记得登录云服务器里把WINDOWS的防火墙关闭或者放行81端口想法:windows服务器里下载nginxwindows版本,然后所有请求......
  • 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
    977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II977.有序数组的平方题目链接:977.有序数组的平方-力扣(LeetCode) 代码:classSolution{public:  vector<int>sortedSquares(vector<int>&nums){​    //intlength=end(nums)-begin(nums);......
  • Day 28 | 491.递增子序列 、46.全排列、 47.全排列 II
    491.递增子序列本题和大家刚做过的90.子集II非常像,但又很不一样,很容易掉坑里。https://programmercarl.com/0491.递增子序列.html视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v给你一个整数数组nums,找出并返回所有该数组中不同的递增子序列,递增子序列中至少有两......
  • 关于iis自动回收机制
    1、iis默认20分钟会自动回收2、启动模式修改为AlwaysRunning 2、设置应用程序池》》高级设置》》回收。设置发生错误禁止回收改为true,禁用重叠回收改为true,固定时间改为0; 3、设置进程模型》超时设置,默认20分钟改为0;最大1740,改为0的时候也是最大1740分钟即29个小时。......
  • qt 简单实验 一个可以向右侧拖拽缩放的矩形
    1.概要目的是设置一个可以拖拽缩放的矩形,这里仅用右侧的一个边模拟这个过程。就是为了抓住核心,这个便解决了,其他的边也是一样的。而这个更能体现原理。2.代码2.1 resizablerectangle.h#ifndefRESIZABLERECTANGLE_H#defineRESIZABLERECTANGLE_H#include<QWidget>#in......
  • HC32L130/HC32L136开发之软件模拟IIC驱动AT24C64
    一、AT24C64电路图二、程序编码1.定义I2C总线连接的GPIO端口/*定义I2C总线连接的GPIO端口,用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚*/#defineRCC_I2C_PORT   SysctrlPeripheralGpio      /*GPIO端口时钟*/#definePORT_I2C_SCL  ......
  • Linux驱动开发笔记(九)IIC子系统及其驱动
    文章目录前言一、IIC驱动框架二、总线驱动2.1iic总线的运行机制2.2重要数据结构2.2.1i2c_driver结构体2.2.2i2c总线结构体2.3匹配规则三、设备树的修改四、设备驱动的编写4.1相关API函数4.1.1i2c_add_adapter()4.1.2i2c_register_driver()4.1.3i2c_transfer......
  • 通讯协议大全(UART,RS485,SPI,IIC)
    参考自: 常见的通讯协议总结(USART、IIC、SPI、485、CAN)-CSDN博客UART那么好用,为什么单片机还需要I2C和SPI?_哔哩哔哩_bilibili5分钟看懂!串口RS232RS485最本质的区别!_哔哩哔哩_bilibili喜欢几位博主老师老师的还请看原贴/原视频数据通信 数据通信是指通过某种传......