算法学习:每日一练 No.223
今天的题目比较简单,可是我的脑子实在太笨了。
223. 矩形面积
要求解的是这两个矩形覆盖的总面积。
用容斥原理可以解决这道题,最终的总面积 = 矩形a的面积 + 矩形b的面积 - a与b相交的面积。
只要求得相交的面积这题就可以宣告结束了,那么该如何用代码去求解呢?
我这个比较笨的思路
令重合部分的矩形为C,要求得C的面积首先要知道边长,边长也是ab两个矩形重合部分的边长。C在X轴上的投影取决于[ax1,ax2]和[bx1,bx2],目的就是求解这两个区间的交集。
区间的交集取决于ab两个矩形的关系,从图上倒是可以清晰的得知ab两个矩形的关系,即ax1 < bx1 < ax2 < bx2,如果扩展到任意两个矩形又应该如何判断呢?
现在我们只关注X轴上的投影区间,我们将ab扩展为平面上任意两个矩形,得到的投影区间的关系如下:
区间关系 | 是否重合 |
---|---|
ax1 < ax2 <= bx1 < bx2 | 不重合 |
ax1 <= bx1 < ax2 <= bx2 | 重合 |
ax1 <= bx1 < bx2 <= ax2 | 重合 |
bx1 <= ax1 < bx2 <= ax2 | 重合 |
bx1 < bx2 <= ax1 < ax2 | 不重合 |
总而言之,如果是重合的情况,我们只需要将数组[ax1,ax2,bx1,bx2]
排序后的中间两项做差,就能得到我们要的边长了。
想起来是这样,不过判断的过程就有些复杂了吧?尝试写一下判断的逻辑。
bool isCoincide(int ax1,int ax2,int bx1,int bx2)
{
if(ax2 <= bx1 || bx2 <= ax1)
{
return false;
}
return true;
}
经过上表的总结,判断不重合比判断重合要方便许多,因为在这道题当中x1一定小于x2,所以不重合的情况只需要判断x2和x1的情况就好了。
X轴的投影区间是否重合可以用上述代码来进行判断,同理,Y轴的情况也可以使用上述代码。
写出来的程序大概是这个样子:
#include <algorithm>
#include <vector>
using namespace std;
class Solution
{
public:
int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
vector<int> coincideX = {ax1, ax2, bx1, bx2};
vector<int> coincideY = {ay1, ay2, by1, by2};
int coincideArea = 0;
if (isCoincide(ax1, ax2, bx1, bx2) && isCoincide(ay1, ay2, by1, by2))
{
sort(coincideX.begin(), coincideX.end());
sort(coincideY.begin(), coincideY.end());
coincideArea = (coincideX[2] - coincideX[1]) * (coincideY[2] - coincideY[1]);
}
return (ax2 - ax1) * (ay2 - ay1) + (bx2 - bx1) * (by2 - by1) - coincideArea;
}
bool isCoincide(int ax1, int ax2, int bx1, int bx2)
{
if (ax2 <= bx1 || bx2 <= ax1)
{
return false;
}
return true;
}
};
int main(int argc, char const *argv[])
{
int ax1 = -3, ay1 = 0, ax2 = 3, ay2 = 4, bx1 = 0, by1 = -1, bx2 = 9, by2 = 2;
Solution s;
int res = s.computeArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
return 0;
}
这样耗费的时间和空间都很多,很不聪明,很不值当,我很讨厌自己,虽然能解出正确的答案。
聪明的解法
看了题解我才明白,可以这么简单。
投影区间的交集嘛,无非就是左端点取值最大的,右端点取值最小的,两者相减即是边长。
没有交集的时候这个值会是负数,最终求解面积的时候将该值与0取一个max()
即可。
直接上代码:
#include <algorithm>
using namespace std;
class Solution {
public:
int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {
int area1 = (ax2 - ax1) * (ay2 - ay1);
int area2 = (bx2 - bx1) * (by2 - by1);
int width3 = std::max(std::min(ax2, bx2) - std::max(ax1, bx1), 0);
int length3 = std::max(std::min(ay2, by2) - std::max(ay1, by1), 0);
return area1 + area2 - width3 * length3;
}
};