【离散化 二维差分】391. 完美矩形

本文涉及知识点

离散化 二维差分

LeetCode391. 完美矩形

给你一个数组 rectangles ,其中 rectangles[i] = [xi, yi, ai, bi] 表示一个坐标轴平行的矩形。这个矩形的左下顶点是 (xi, yi) ,右上顶点是 (ai, bi) 。
如果所有矩形一起精确覆盖了某个矩形区域,则返回 true ;否则,返回 false 。
示例 1:
输入:rectangles = [[1,1,3,3],[3,1,4,2],[3,2,4,4],[1,3,2,4],[2,3,3,4]]
在这里插入图片描述

输出:true
解释:5 个矩形一起可以精确地覆盖一个矩形区域。
示例 2:
在这里插入图片描述

输入:rectangles = [[1,1,2,3],[1,3,2,4],[3,1,4,2],[3,2,4,4]]
输出:false
解释:两个矩形之间有间隔,无法覆盖成一个矩形。
示例 3:
输入:rectangles = [[1,1,3,3],[3,1,4,2],[1,3,2,4],[2,2,4,4]]
输出:false
解释:因为中间有相交区域,虽然形成了矩形,但不是精确覆盖。
在这里插入图片描述

提示:
1 <= rectangles.length <= 2 * 104
rectangles[i].length == 4
-105 <= xi, yi, ai, bi <= 105

离散化+二维差分

离散化:集合xs记录所有xi,ai,并排序。xs[i]映射为i。 yi,bi类似。
令ix=min(xi) iy = min(yi) ax = max(ai) ay = max(bi)
则矩形:(ix,iy) (ax,ya)都只被覆盖了一次。否则非法。
注意: xi等于ai或yi等于bi,无需排除。

代码

核心代码

class CDiscretize //离散化
{
public:
	CDiscretize(vector<int> nums)
	{
		sort(nums.begin(), nums.end());
		nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
		m_nums = nums;
		for (int i = 0; i < nums.size(); i++)
		{
			m_mValueToIndex[nums[i]] = i;
		}
	}
	int operator[](const int value)const
	{
		auto it = m_mValueToIndex.find(value);
		if (m_mValueToIndex.end() == it)
		{
			return -1;
		}
		return it->second;
	}
	int size()const
	{
		return m_mValueToIndex.size();
	}
	vector<int> m_nums;
protected:	
	unordered_map<int, int> m_mValueToIndex;
};

template<class T = int >
class CDiff2
{
public:
	CDiff2(int r, int c) :m_iR(r), m_iC(c) {
		m_vDiff.assign(m_iR, vector<T>(m_iC));
	}
	void Set(int r1, int c1, int r2Exinc, int c2Exinc, int iAdd) {
		m_vDiff[r1][c1] += iAdd;
		m_vDiff[r2Exinc][c2Exinc] += iAdd;
		m_vDiff[r1][c2Exinc] -= iAdd;
		m_vDiff[r2Exinc][c1] -= iAdd;
	}
	vector<vector<T>> Ans()const {
		vector<vector<T>> res(m_iR, vector<T>(m_iC));
		vector<T> vCols(m_iC);
		for (int r = 0; r < m_iR; r++) {
			T iSum = 0;
			for (int c = 0; c < m_iC; c++) {
				vCols[c] += m_vDiff[r][c];
				iSum += vCols[c];
				res[r][c] = iSum;
			}
		}
		return res;
	}

	const int m_iR, m_iC;
protected:
	vector<vector<T>> m_vDiff;
};

template<class ELE, class ELE2>
void MinSelf(ELE* seft, const ELE2& other)
{
	*seft = min(*seft, (ELE)other);
}

template<class ELE>
void MaxSelf(ELE* seft, const ELE& other)
{
	*seft = max(*seft, other);
}


class Solution {
public:
	bool isRectangleCover(vector<vector<int>>& rectangles) {
		vector<int> xs, ys;
		for (const auto& v : rectangles) {
			xs.emplace_back(v[0]);
			xs.emplace_back(v[2]);
			ys.emplace_back(v[1]);
			ys.emplace_back(v[3]);
		}
		CDiscretize dx(xs), dy(ys);
		int ix = INT_MAX, iy = INT_MAX, ax = INT_MIN, ay = INT_MIN;
		CDiff2<int> diff2(dx.size() + 1, dy.size() + 1);
		for (const auto& v : rectangles) {
			const int i0 = dx[v[0]];
			const int i2 = dx[v[2]];
			const int i1 = dy[v[1]];
			const int i3 = dy[v[3]];
			diff2.Set(i0, i1, i2, i3,1);
			MinSelf(&ix, i0);
			MinSelf(&iy, i1);
			MaxSelf(&ax, i2);
			MaxSelf(&ay, i3);
		}
		auto ans = diff2.Ans();
		for (int x = ix; x < ax; x++) {
			for (int y = iy; y < ay; y++) {
				if (1 != ans[x][y]) { return false; }
			}
		}
		return true;
	}
};

单元测试

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>> rectangles;
	TEST_CLASS(UnitTest)
	{
	public:
		TEST_METHOD(TestMethod0)
		{
			rectangles = { {1,1,3,3},{3,1,4,2},{3,2,4,4},{1,3,2,4},{2,3,3,4} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx( true, res);
		}
		TEST_METHOD(TestMethod1)
		{
			rectangles = { {1,1,2,3},{1,3,2,4},{3,1,4,2},{3,2,4,4} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
		TEST_METHOD(TestMethod2)
		{
			rectangles = { {1,1,3,3},{3,1,4,2},{1,3,2,4},{2,2,4,4} 	};
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
		TEST_METHOD(TestMethod3)
		{
			rectangles = { {0,0,1,1},{0,2,1,3},{1,1,2,2},{2,0,3,1},{2,2,3,3},{1,0,2,3},{0,1,3,2} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
		TEST_METHOD(TestMethod4)
		{
			rectangles = { {0,0,1,1},{0,2,1,3},{1,1,2,2},{2,0,3,1},{2,2,3,3},{1,0,2,3},{0,1,3,2} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
		TEST_METHOD(TestMethod5)
		{
			rectangles = { {0,0,3,3},{1,1,2,2},{1,1,2,2} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
		TEST_METHOD(TestMethod6)
		{
			rectangles = { {0,0,1,1},{0,0,1,1},{1,1,2,2},{1,1,2,2} };
			auto res = Solution().isRectangleCover(rectangles);
			AssertEx(false, res);
		}
	};
}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

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

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
《喜缺全书算法册》以原理、正确性证明、总结为主。
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

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

二维泊松方程是一种描述空间区域内电势分布的数学模型,可以通过有限差分法在MATLAB中求解。有限差分法是一种常用的数值解法,它将连续的问题离散化,将求解区域划分为网格,通过近似代替微分方程中的导数项。 首先,我们需要将求解区域划分为均匀的网格,将二维泊松方程转化为差分方程。假设有一个M × N的矩形网格,其中M表示沿x方向的离散点数,N表示沿y方向的离散点数。我们将二维泊松方程表示为: (1/h^2)*(U(i+1,j) + U(i-1,j) + U(i,j+1) + U(i,j-1) - 4U(i,j)) = f(i,j) 其中,U(i,j)表示网格点(i,j)处的电势值,f(i,j)表示该点的电荷密度。h为网格的步长。 根据差分方法的思想,我们可以通过迭代逐步求解电势分布。在迭代的过程中,将边界条件和初始猜测的电势值带入上述差分方程,根据迭代公式更新网格点的电势值,直至达到迭代精度要求。 在MATLAB中,我们可以使用双重循环来实现迭代计算。首先,根据边界条件和初始猜测的电势值,初始化整个网格。然后,在每次迭代中,使用双重循环遍历所有内部网格点,根据上述差分方程计算每个点的电势值。最后,根据所设定的迭代精度要求,判断是否满足迭代结束条件。 通过使用有限差分法求解二维泊松方程,我们可以在MATLAB中获得电势分布的数值解。这种数值解法相对比较简单且高效,可以应用于各种二维空间的电势分布模拟和计算中。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闻缺陷则喜何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值