Skip to content

Commit 6db80c0

Browse files
committed
✨feat: add 850
1 parent 8595d19 commit 6db80c0

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

Index/扫描线问题.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | -------- |
33
| [218. 天际线问题](https://leetcode-cn.com/problems/the-skyline-problem/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/the-skyline-problem/solution/gong-shui-san-xie-sao-miao-xian-suan-fa-0z6xc/) | 困难 | 🤩🤩🤩 |
44
| [391. 完美矩形](https://leetcode-cn.com/problems/perfect-rectangle/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/perfect-rectangle/solution/gong-shui-san-xie-chang-gui-sao-miao-xia-p4q4/) | 困难 | 🤩🤩🤩🤩 |
5+
| [850. 矩形面积 II](https://leetcode.cn/problems/rectangle-area-ii/) | [LeetCode 题解链接](https://leetcode.cn/problems/rectangle-area-ii/solution/gong-shui-san-xie-by-ac_oier-9r36/) | 困难 | 🤩🤩🤩🤩🤩 |
56

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[850. 矩形面积 II](https://leetcode.cn/problems/rectangle-area-ii/solution/gong-shui-san-xie-by-ac_oier-9r36/)** ,难度为 **困难**
4+
5+
Tag : 「扫描线」
6+
7+
8+
9+
我们给出了一个(轴对齐的)二维矩形列表 `rectangles`。 对于 $rectangle[i] = [x_1, y_1, x_2, y_2]$,其中$(x_1, y_1)$ 是矩形 `i` 左下角的坐标,$ (x_{i1}, y_{i1})$ 是该矩形 左下角 的坐标,$ (x_{i2}, y_{i2})$ 是该矩形 右上角 的坐标。
10+
11+
计算平面中所有 `rectangles` 所覆盖的 总面积 。任何被两个或多个矩形覆盖的区域应只计算 一次 。
12+
13+
返回 总面积 。因为答案可能太大,返回 $10^9 + 7$ 的 模 。
14+
15+
示例 1:
16+
![](https://s3-lc-upload.s3.amazonaws.com/uploads/2018/06/06/rectangle_area_ii_pic.png)
17+
```
18+
输入:rectangles = [[0,0,2,2],[1,0,2,3],[1,0,3,1]]
19+
20+
输出:6
21+
22+
解释:如图所示,三个矩形覆盖了总面积为6的区域。
23+
从(1,1)到(2,2),绿色矩形和红色矩形重叠。
24+
从(1,0)到(2,3),三个矩形都重叠。
25+
```
26+
示例 2:
27+
```
28+
输入:rectangles = [[0,0,1000000000,1000000000]]
29+
30+
输出:49
31+
32+
解释:答案是 1018 对 (109 + 7) 取模的结果, 即 49 。
33+
```
34+
35+
提示:
36+
* $1 <= rectangles.length <= 200$
37+
* $rectanges[i].length = 4$
38+
* $0 <= x_{i1}, y_{i1}, x_{i2}, y_{i2} <= 10^9$
39+
* 矩形叠加覆盖后的总面积不会超越 $2^{63} - 1$ ,这意味着可以用一个 `64` 位有符号整数来保存面积结果。
40+
41+
---
42+
43+
## 扫描线
44+
45+
这是一道「扫描线」模板题。
46+
47+
将所有给定的矩形的左右边对应的 `x` 端点提取出来并排序,每个端点可看作是一条竖直的线段(红色),问题转换为求解「由多条竖直线段分割开」的多个矩形的面积总和(黄色):
48+
49+
![image.png](https://pic.leetcode-cn.com/1663294074-shUiEA-image.png)
50+
51+
相邻线段之间的宽度为单个矩形的「宽度」(通过 `x` 差值直接算得),问题转换为求该区间内高度的并集(即矩形的高度)。
52+
53+
由于数据范围只有 $200$,我们可以对给定的所有矩形进行遍历,统计所有对该矩形有贡献的 `y` 值线段(即有哪些 `rs[i]` 落在该矩形中),再对线段进行求交集(总长度),即可计算出该矩形的「高度」,从而计算出来该矩形的面积。
54+
55+
![image.png](https://pic.leetcode-cn.com/1663293673-WeoWgG-image.png)
56+
57+
Java 代码:
58+
```Java
59+
class Solution {
60+
int MOD = (int)1e9+7;
61+
public int rectangleArea(int[][] rs) {
62+
List<Integer> list = new ArrayList<>();
63+
for (int[] info : rs) {
64+
list.add(info[0]); list.add(info[2]);
65+
}
66+
Collections.sort(list);
67+
long ans = 0;
68+
for (int i = 1; i < list.size(); i++) {
69+
int a = list.get(i - 1), b = list.get(i), len = b - a;
70+
if (len == 0) continue;
71+
List<int[]> lines = new ArrayList<>();
72+
for (int[] info : rs) {
73+
if (info[0] <= a && b <= info[2]) lines.add(new int[]{info[1], info[3]});
74+
}
75+
Collections.sort(lines, (l1, l2)->{
76+
return l1[0] != l2[0] ? l1[0] - l2[0] : l1[1] - l2[1];
77+
});
78+
long tot = 0, l = -1, r = -1;
79+
for (int[] cur : lines) {
80+
if (cur[0] > r) {
81+
tot += r - l;
82+
l = cur[0]; r = cur[1];
83+
} else if (cur[1] > r) {
84+
r = cur[1];
85+
}
86+
}
87+
tot += r - l;
88+
ans += tot * len;
89+
ans %= MOD;
90+
}
91+
return (int) ans;
92+
}
93+
}
94+
```
95+
TypeScript 代码:
96+
```TypeScript
97+
const MOD = BigInt(1e9+7)
98+
function rectangleArea(rs: number[][]): number {
99+
const list = new Array<number>()
100+
for (let info of rs) {
101+
list.push(info[0]); list.push(info[2]);
102+
}
103+
list.sort((a,b)=>a-b)
104+
let ans = 0n
105+
for (let i = 1; i < list.length; i++) {
106+
const a = list[i - 1], b = list[i], len = b - a
107+
if (len == 0) continue
108+
const lines = new Array<number[]>()
109+
for (let info of rs) {
110+
if (info[0] <= a && b <= info[2]) lines.push([info[1], info[3]])
111+
}
112+
lines.sort((l1,l2)=>{
113+
return l1[0] != l2[0] ? l1[0] - l2[0] : l1[1] - l2[1]
114+
})
115+
let tot = 0n, l = -1, r = -1
116+
for (let cur of lines) {
117+
if (cur[0] > r) {
118+
tot += BigInt(r - l)
119+
l = cur[0]; r = cur[1]
120+
} else if (cur[1] > r) {
121+
r = cur[1]
122+
}
123+
}
124+
tot += BigInt(r - l)
125+
ans += tot * BigInt(len)
126+
ans %= MOD
127+
}
128+
return Number(ans)
129+
};
130+
```
131+
Python 代码:
132+
```Python
133+
class Solution:
134+
def rectangleArea(self, rs: List[List[int]]) -> int:
135+
ps = []
136+
for info in rs:
137+
ps.append(info[0])
138+
ps.append(info[2])
139+
ps.sort()
140+
ans = 0
141+
for i in range(1, len(ps)):
142+
a, b = ps[i - 1], ps[i]
143+
width = b - a
144+
if width == 0:
145+
continue
146+
lines = [(info[1], info[3]) for info in rs if info[0] <= a and b <= info[2]]
147+
lines.sort()
148+
height, l, r = 0, -1, -1
149+
for cur in lines:
150+
if cur[0] > r:
151+
height += r - l
152+
l, r = cur
153+
elif cur[1] > r:
154+
r = cur[1]
155+
height += r - l
156+
ans += height * width
157+
return ans % 1000000007
158+
```
159+
Go 代码:
160+
```Go
161+
const MOD = int64(1e9 + 7)
162+
func rectangleArea(rectangles [][]int) int {
163+
list := []int{}
164+
for _, info := range rectangles {
165+
list = append(list, info[0])
166+
list = append(list, info[2])
167+
}
168+
sort.Ints(list)
169+
ans := int64(0)
170+
for i := 1; i < len(list); i++ {
171+
a, b, length := list[i - 1], list[i], list[i] - list[i - 1]
172+
if length == 0 {
173+
continue
174+
}
175+
lines := [][]int{}
176+
for _, info := range rectangles {
177+
if info[0] <= a && b <= info[2] {
178+
lines = append(lines, []int{info[1], info[3]})
179+
}
180+
}
181+
sort.Slice(lines, func(i,j int) bool {
182+
if lines[i][0] != lines[j][0] {
183+
return lines[i][0] - lines[j][0] < 0
184+
}
185+
return lines[i][1] - lines[j][1] < 0
186+
})
187+
total, l, r := int64(0), -1, -1
188+
for _, cur := range lines {
189+
if cur[0] > r {
190+
total += int64(r - l)
191+
l, r = cur[0], cur[1]
192+
} else if cur[1] > r {
193+
r = cur[1]
194+
}
195+
}
196+
total += int64(r - l)
197+
ans += total * int64(length)
198+
ans %= MOD
199+
}
200+
return int(ans)
201+
}
202+
```
203+
* 时间复杂度:预处理所有扫描线的复杂度为 $O(n\log{n})$;处理所有相邻的扫描线,并计算相邻扫描线形成的矩形面积复杂度为 $O(n\log{n})$ 。整体复杂度为 $O(n^2\log{n})$
204+
* 空间复杂度:$O(n)$
205+
206+
---
207+
208+
### 最后
209+
210+
这是我们「刷穿 LeetCode」系列文章的第 `No.850` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
211+
212+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
213+
214+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
215+
216+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
217+

0 commit comments

Comments
 (0)