JAVA程序设计:矩形面积 II(LeetCode:850)

我们给出了一个(轴对齐的)矩形列表 rectangles 。 对于 rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标,(x2,y2)是该矩形右上角的坐标。

找出平面中所有矩形叠加覆盖后的总面积。 由于答案可能太大,请返回它对 10 ^ 9 + 7 取模的结果。

示例 1:

输入:[[0,0,2,2],[1,0,2,3],[1,0,3,1]]
输出:6
解释:如图所示。
示例 2:

输入:[[0,0,1000000000,1000000000]]
输出:49
解释:答案是 10^18 对 (10^9 + 7) 取模的结果, 即 (10^9)^2 → (-7)^2 = 49 。
提示:

1 <= rectangles.length <= 200
rectanges[i].length = 4
0 <= rectangles[i][j] <= 10^9
矩形叠加覆盖后的总面积不会超越 2^63 - 1 ,这意味着可以用一个 64 位有符号整数来保存面积结果。

思路:裸的线段树+扫描线,具体可以看我这篇博客

class Solution {
	
	class node implements Comparable<node> {
		long l,r,h;
		int d;
		public node(long l,long r,long h,int d) {
			this.l=l;
			this.r=r;
			this.h=h;
			this.d=d;
		}
		@Override
		public int compareTo(node o) {
			// TODO 自动生成的方法存根
			if(h==o.h) return 0;
			return h<o.h?-1:1;
		}
	}
	
	private int[] cnt;
	private long[] x;
	private node[] nodes;
	private long[] sum;
	
	private static int maxn=205;
	private static int mod=1000000007;
	
    public int rectangleArea(int[][] rectangles) {
    	
    	int len1=0,len2=0;
    	cnt=new int[maxn*4];
    	x=new long[maxn*4];
    	sum=new long[maxn*4];
    	nodes=new node[maxn*2+1];
    	int n=rectangles.length;
    	
    	for(int i=0;i<n;i++) {
    		x[++len1]=rectangles[i][0];
    		x[++len1]=rectangles[i][2];
    		nodes[++len2]=new node(rectangles[i][0],rectangles[i][2],rectangles[i][1],1);
    		nodes[++len2]=new node(rectangles[i][0],rectangles[i][2],rectangles[i][3],-1);
    	}
    	
    	Arrays.parallelSort(x,1,len1+1);
    	Arrays.parallelSort(nodes,1,len2+1);
    	
    	int k=1;
    	for(int i=2;i<=len1;i++)
    		if(x[i]!=x[i-1])
    			x[++k]=x[i];
    	
    	build(1,1,k-1); //k个不同的x坐标,构成了k-1个区域
    	
    	long ans=0;
    	for(int i=1;i<len2;i++) {
    		int l=find(nodes[i].l,k);
    		int r=find(nodes[i].r,k)-1;
    		if(l<=r) update(l,r,nodes[i].d,1,1,k-1);
    		ans=(ans+(long)(sum[1]*(nodes[i+1].h-nodes[i].h))%mod)%mod;
    	}
    	
    	return (int)ans;
    }
    
    private void update(int ls,int rs,int v,int id,int l,int r) {
    	
    	if(ls<=l && rs>=r) {
    		if(cnt[id]!=-1) {
    			cnt[id]+=v;	
    			sum[id]=(cnt[id]!=0?(x[r+1]-x[l]):0);
    			return;
    		}
    	}
    	
    	pushdown(id,l,r);
    	
    	int m=(l+r)/2;
    	if(ls<=m)
    		update(ls,rs,v,id*2,l,m);
    	if(rs>m)
    		update(ls,rs,v,id*2+1,m+1,r);
    	
    	pushup(id,l,r);
    	
    }
    
    private void pushdown(int id,int l,int r) {
    	
    	int m=(l+r)/2;
    	if(cnt[id]!=-1) {
    		cnt[id*2]=cnt[id*2+1]=cnt[id];
    		sum[id*2]=(cnt[id]!=0?(x[m+1]-x[l]):0);
    		sum[id*2+1]=(cnt[id]!=0?(x[r+1]-x[m+1]):0);
    	}
    	
    }
    
    private int find(double key,int n) {
    	
    	int l=1,r=n;
    	while(l<=r) {
    		int m=(l+r)/2;
    		if(x[m]==key)
    			return m;
    		else if(x[m]>key)
    			r=m-1;
    		else
    			l=m+1;
    	}
    	
    	return -1;
    	
    }
    
    private void build(int id,int l,int r) {
    	
    	if(l==r) {
    		cnt[id]=0;
    		sum[id]=0;
    		return;
    	}
    	int m=(l+r)/2;
    	build(id*2,l,m);
    	build(id*2+1,m+1,r);
    	pushup(id,l,r);
    	
    }
    
    private void pushup(int id,int l,int r) {
    	
    	if(cnt[id*2]==-1 || cnt[id*2+1]==-1)
    		cnt[id]=-1;
    	else if(cnt[id*2]!=cnt[id*2+1])
    		cnt[id]=-1;
    	else
    		cnt[id]=cnt[id*2];
    	sum[id]=sum[id*2]+sum[id*2+1];
    	
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值