• leetcode 850. Rectangle Area II


    给定一些矩形2 求覆盖面积 矩形不超过200个

    1#

    算法1 朴素思想 虽然朴素但是代码却有意思
    利用容斥原理
    复杂度高达 N*2^N

    class Solution:
        def intersect(rec1,rec2):
            return [max(rec1[1],rec2[1]),
                        max(rec1[2],rec2[2]),
                        min(rec1[3],rec2[3]),
                        min(rec1[4],rec2[4]
                        ]
    #这里是两个矩形的两点式求 矩形的相交子矩形 *非常值得思考
    
        def area(rec):
            dx=max(0,rec[2]-rec[0])
            dy=max(0,rec[3]-rec[1])
            return dx*dy
    
        ans=0
        
        for size in range(1,len(rectangles)+1):
    
            for group in itertools.combinations(rectangles,size):
                ans = ans +(-1)** (size+1) * area(reduce(intersect,group))
        return ans%mod             
    

    2#

    点位压缩,压缩后进行暴力循环
    同时压缩x和y

    最后返回

    class Solution(object):
        def rectangleArea(self, rectangles):
            N = len(rectangles)
            Xvals, Yvals = set(), set()
            for x1, y1, x2, y2 in rectangles:
                Xvals.add(x1); Xvals.add(x2)
                Yvals.add(y1); Yvals.add(y2)
    
            imapx = sorted(Xvals)
            imapy = sorted(Yvals)
            mapx = {x: i for i, x in enumerate(imapx)}
            mapy = {y: i for i, y in enumerate(imapy)}
    
            grid = [[0] * len(imapy) for _ in imapx]
            for x1, y1, x2, y2 in rectangles:
                for x in xrange(mapx[x1], mapx[x2]):
                    for y in xrange(mapy[y1], mapy[y2]):
                        grid[x][y] = 1
    
            ans = 0
            for x, row in enumerate(grid):
                for y, val in enumerate(row):
                    if val:
                        ans += (imapx[x+1] - imapx[x]) * (imapy[y+1] - imapy[y])
            return ans % (10**9 + 7)
    

    N^3

    3#

    算法3 扫描线算法
    将每一个矩形看作一个 "事件" 这样的事件

    class Solution(object):
        def rectangleArea(self, rectangles):
            # Populate events
            OPEN, CLOSE = 0, 1
            events = []
            for x1, y1, x2, y2 in rectangles:
                events.append((y1, OPEN, x1, x2))
                events.append((y2, CLOSE, x1, x2))
            events.sort()
    
            def query():
                ans = 0
                cur = -1
                for x1, x2 in active:
                    cur = max(cur, x1)
                    ans += max(0, x2 - cur)
                    cur = max(cur, x2)
                return ans
    
            active = []
            cur_y = events[0][0]
            ans = 0
            for y, typ, x1, x2 in events:
                # For all vertical ground covered, update answer
                ans += query() * (y - cur_y)
    
                # Update active intervals
                if typ is OPEN:
                    active.append((x1, x2))
                    active.sort()
                else:    
                    active.remove((x1, x2))
    
                cur_y = y
    
            return ans % (10**9 + 7)
    

    4#

    注意到刚才的3算法中使用了 区间维护的算法 这里使用线段树维护这个区间
    使得达到 NlogN

    下面是py 实现线段树

    class Node:
        def __init__(self,start,end):
            self.start=start
            self.end=end
            self.mid=(start+end)//2
            
            self.active_count=0
            self.totle =0
            
            self._left=None
            self._right=None
        @property
        def right(self):    
            self._right= self._right or Node(self.mid,self.end)
            return self._right
        
            
        @property
        def left(self):
            self._left=self._left or Node(self.start,self.mid)
            return self._left
        
        #更新 i j 合适的区域 + val     
        #同时返回 i j 之间的x大小
        def update(self,i,j,val):
            print(str(i)+" "+str(j))
            if(i>=j):
                return 0
        
            if(i==self.start and j==self.end):
                self.active_count = self.active_count + val 
            else:
                self.left .update( i,  min( self.mid ,j )  , val )
                self.right.update( max(self.mid,i)       ,j, val ) 
                
            #当前区域有 至少一个覆盖
            if(self.active_count>0):
    
                self.totle= X[self.end]-X[self.start]
            else:
                
                self.totle= self.left.totle + self.right.totle 
                
            return self.totle 
        
            
            
            
    
    class Solution:
        def rectangleArea(self, rectangles):
            """
            :type rectangles: List[List[int]]
            :rtype: int
            """
            ACTIVE = 1
            DEACTIVE = -1 
            global X 
            X=set()
            events=[]
            for rect in rectangles:
                X.add(rect[0])
                X.add(rect[2])
                
                events.append([rect[1],rect[0],rect[2],ACTIVE])
                events.append([rect[3],rect[0],rect[2],DEACTIVE])
                
            X=sorted(X)
            events=sorted(events)
            pos2idx={ x:i for i,x in enumerate(X) }        
            
            sum_area=0
            y_cur=0        
            y_cur_next=0
            x_cur=0
            
            SegNode = Node(0,len(pos2idx))
            print(pos2idx)
            for event in events:
                y_cur_next=event[0]
                sum_area=sum_area+(y_cur_next-y_cur)*x_cur
    
                x_cur=SegNode.update(pos2idx[event[1]],pos2idx[event[2]],event[3])
                print(event)
                print(x_cur)
                
                y_cur=y_cur_next
                
            return sum_area%(1000000000 + 7)
            
            
    

    注意这里的 下标实际意义不是 容器 而是 标志
    所以 会有
    start mid
    mid end
    这样的划分方法 应该注意

    另外利用python 的 property 很方便的写出了懒申请策略

    (python 做点集压缩真的方便
    付:
    leetcode 56. Merge Intervals On 求overlap

  • 相关阅读:
    unity的#pragma strict,#pragma downcast等指令分享
    Unity3d 添加多相机后编译警告
    Invoke计时器
    unity3d UI自动适合屏幕分辨率
    实现卷轴效果的脚本
    .unity3d格式的导出与加载
    Linux 网络编程
    姿态解算基本完成,程序编写笔记
    验证网络上四元数的正确性
    2440 模拟IIC 可以读取 L3G4200D ,ADXL345
  • 原文地址:https://www.cnblogs.com/sfzyk/p/9321181.html
Copyright © 2020-2023  润新知