利用列表数据去重的原理解决LeetCode题库第391题完美矩形问题

文章介绍了如何通过分解矩形为小矩形,利用集合去重的方法,判断一组矩形是否能精确覆盖成一个完美矩形,关键在于比较所有矩形面积之和、最大矩形面积以及去重后的小矩形面积是否相等。
摘要由CSDN通过智能技术生成

391. 完美矩形

难度:困难

给你一个数组 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

解释:因为中间有相交区域,虽然形成了矩形,但不是精确覆盖。

分析:

这个问题有些难度,所以其标志为困难,通过率为46.1%。

看了这个题目,有几天没动手,但总在闲下来的时候,思考其处理。

首先我想到的是对给定的一系列矩形进行排序,然后按从左到右,从下到上的顺序依次拼接,看能不能拼接成一个完美矩形,或许这也是一种处理思路,但我还是没有付之行动,总觉得有些不太好处理。

后来我又想到一个方法,那就是既然给定的一系列矩形能够拼接成一个完美矩形,那么这些矩形的面积和一定等完美矩形的面积,如果相等就可以判定能够组成完美矩形,如果不相等,那就不能组成完美矩形。

正自以为得计,结果发现如果是上面的这个图形的话,虽说一系列矩形的面积和等于最大矩形面积,但中间有重叠的部分,并没有构成完美矩形,所以仅仅让矩形面积和等于最大矩形面积,还不能判断就能够组成完美矩形。

这让我联想到判断一个列表中有没有重复元素的方法,先将列表转换为集合,如果有重复就会自动去掉重复元素,这样元素个数就会减少,以元素个数是否减少来判断有没有重复元素,或许这里可以用到这种思想。

基于这种考虑,所以我又把每一个矩形分解为面积为1的小矩形,并用每一个小矩形的左下角坐标组成的元组,形成一个列表,是用左下角坐标组成元组而不是组成列表,是因为只有列表元素为不可变的对象才能进行这种转换,否则会出现“TypeError: unhashable type: 'list'”的错误提示。将所有矩形分解为这种小矩形并保存到一个列表中之后,然后转换为集合去重,再统计其元素个数,即可得到面积。如果这个面积与所有矩形面积之和相等,则说明没有重叠部分。

最后判断能不能构成完美矩形,只需要比较给定的一系列矩形组成的最大矩形区域面积,所有矩形面积和与去重之后的面积三者是否相等即可,如果三者相等,则能够构成完美矩形,否则不能构成完美矩形。

程序如下

#求一个矩形的面积
def s_rectangle(rectangle):
    m=rectangle[2]-rectangle[0]
    n=rectangle[3]-rectangle[1]
    return m*n

#从给定的一系列矩形中返回最大面积的矩形区域
def max_rectangle(rectangles):
    minx=min(list(map(lambda b:b[0],rectangles)))
    miny=min(list(map(lambda b:b[1],rectangles)))
    maxx=max(list(map(lambda b:b[2],rectangles)))
    maxy=max(list(map(lambda b:b[3],rectangles)))
    return [minx,miny,maxx,maxy]

#将一个矩形分解成面积为1的矩形集合,每个矩形仅用
#由左下角坐标形成的元组代表,返回左下角坐标的列表
def fj_rectangle(rectangle):
    x1=rectangle[0]
    x2=rectangle[2]
    y1=rectangle[1]
    y2=rectangle[3]
    a=[(i,j) for i in range(x1,x2) for j in range(y1,y2)]
    return a   

#对给出的一系列矩形,计算每个矩形的面积并求和
#返回总面积和将所有矩形分解为面积为1的矩形的列表
def s(rectangles):
    s1=0
    b=[]
    for i in rectangles:
        s1=s1+s_rectangle(i)
        b.extend(fj_rectangle(i))
    return s1,b

def pd(rectangles):
    #找出系列矩形的最大矩形区域并求出最大面积
    rm=max_rectangle(rectangles)
    sm=s_rectangle(rm)
    #求出所有矩形的总面积和分解成面积为1的矩形列表
    sf,a=s(rectangles)
    #将矩形重叠的部分去掉之后求出其面积
    b=len(set(a))    
    if sm==sf==b:
        return True
    else:
        return False
    
    
rectangles=eval(input('pls input rectangles='))
print(pd(rectangles))

运行实例1:

pls input rectangles=[[1,1,3,3],[3,1,4,2],[3,2,4,4],[1,3,2,4],[2,3,3,4]]

True

运行实例2:

pls input rectangles=[[1,1,3,3],[3,1,4,2],[1,3,2,4],[2,2,4,4]]

False

感悟:

碰到困难,要迎难而上,多思考,多尝试。

要善于联想,多作知识的迁移,也只有多迁移,才能融会贯通,他山之石,可以攻玉。

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值