LeetCode每日一题(850. Rectangle Area II)

You are given a 2D array of axis-aligned rectangles. Each rectangle[i] = [xi1, yi1, xi2, yi2] denotes the ith rectangle where (xi1, yi1) are the coordinates of the bottom-left corner, and (xi2, yi2) are the coordinates of the top-right corner.

Calculate the total area covered by all rectangles in the plane. Any area covered by two or more rectangles should only be counted once.

Return the total area. Since the answer may be too large, return it modulo 109 + 7.

Example 1:

Input: rectangles = [[0,0,2,2],[1,0,2,3],[1,0,3,1]]
Output: 6

Explanation: A total area of 6 is covered by all three rectangles, as illustrated in the picture.
From (1,1) to (2,2), the green and red rectangles overlap.
From (1,0) to (2,3), all three rectangles overlap.

Example 2:

Input: rectangles = [[0,0,1000000000,1000000000]]
Output: 49

Explanation: The answer is 1018 modulo (109 + 7), which is 49.

Constraints:

  • 1 <= rectangles.length <= 200
  • rectanges[i].length == 4
  • 0 <= xi1, yi1, xi2, yi2 <= 109

我们将整个题想象成一个扫描过程, 从下向上扫描, 每次扫描的高度取决于 rectangles 中出现的所有 y 值, 将这些 y 值排序, 相邻两个 y 值之间的差值就是每次的扫描高度。 我们将每个正方形的上下边视作两种不同的事件, 下边为开始, 上边为结束, 当下边进入扫描范围之后, 当前正方形的左右两个边(x_start, x_end), 开始影响结果, 当上边离开扫描范围之后, 当前正方形的左右两个边(x_start, x_end), 结束对结果的影响。 因为有重叠的情况, 所以我们需要用一个数组来记录实际的影响范围。



use std::collections::{HashMap, HashSet};

const M: i64 = 1000000007;

impl Solution {
    fn compress_coordinates(coordinates: Vec<i32>) -> (HashMap<i32, usize>, HashMap<usize, i32>) {
        let set: HashSet<i32> = coordinates.into_iter().collect();
        let mut l: Vec<i32> = set.into_iter().collect();
        l.sort();
        l.into_iter().enumerate().fold((HashMap::new(), HashMap::new()), |(mut indices, mut coords), (i, v)| {
            indices.insert(v, i);
            coords.insert(i, v);
            (indices, coords)
        })
    }
    pub fn rectangle_area(rectangles: Vec<Vec<i32>>) -> i32 {
        let xs = rectangles.iter().fold(Vec::new(), |mut xs, rect| {
            xs.push(rect[0]);
            xs.push(rect[2]);
            xs
        });
        let (indices, coords) = Solution::compress_coordinates(xs);
        let mut events: Vec<(i32, &str, i32, i32)> = rectangles.iter().map(|r| vec![(r[1], "OPEN", r[0], r[2]), (r[3], "CLOSE", r[0], r[2])]).flatten().collect();
        events.sort();
        let mut gradations = vec![0; indices.len()];
        let mut curr_y = events[0].0;
        let mut ans = 0;
        for (y, typ, x_start, x_end) in events {
            for i in 0..gradations.len() - 1 {
                if gradations[i] > 0 {
                    let &x_coord_1 = coords.get(&i).unwrap();
                    let &x_coord_2 = coords.get(&(i + 1)).unwrap();
                    ans += (x_coord_2 - x_coord_1) as i64 * (y - curr_y) as i64;
                    ans %= M;
                }
            }
            if typ == "OPEN" {
                for i in *indices.get(&x_start).unwrap()..*indices.get(&x_end).unwrap() {
                    gradations[i] += 1;
                }
            } else {
                for i in *indices.get(&x_start).unwrap()..*indices.get(&x_end).unwrap() {
                    gradations[i] -= 1;
                }
            }
            curr_y = y;
        }
        ans as i32
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值