Medium
题目描述
给你一个二维整数数组 squares。每个 squares[i] = [xi, yi, li] 表示一个与 x 轴平行的正方形的左下角坐标和边长。
找到一条水平线的最小 y 坐标值,使得线上方正方形的总面积等于线下方正方形的总面积。
答案误差在 10^-5 范围内将被接受。
注意: 正方形可能重叠。重叠的区域应该被多次计算。
示例 1:
输入:squares = [[0,0,1],[2,2,1]]
输出:1.00000
解释:y = 1 和 y = 2 之间的任何水平线上方都有 1 个单位面积,下方也有 1 个单位面积。最低选项是 1。
示例 2:
输入:squares = [[0,0,2],[1,1,1]]
输出:1.16667
解释:
- 线下方面积:7/6 * 2 (红色) + 1/6 (蓝色) = 15/6 = 2.5
- 线上方面积:5/6 * 2 (红色) + 5/6 (蓝色) = 15/6 = 2.5
由于线上方和下方的面积相等,输出为 7/6 = 1.16667。
提示:
1 <= squares.length <= 5 * 10^4squares[i] = [xi, yi, li]squares[i].length == 30 <= xi, yi <= 10^91 <= li <= 10^9- 所有正方形的总面积不会超过 10^12
解题思路
解题思路
这道题需要找到一条水平线,使得线上方和下方的正方形面积相等。关键在于如何计算给定 y 坐标处的上下面积分布。
核心思路:
- 离散化关键点:收集所有正方形的上边界和下边界 y 坐标,这些是面积变化的关键点
- 二分搜索:在这些关键点之间进行二分搜索,寻找使上下面积相等的分割线
- 面积计算:对于任意 y 坐标,计算每个正方形被分割线切分后的上下部分面积
面积计算方法:
对于正方形 [x, y, l]:
- 如果分割线 y 坐标为
line_y - 下方面积:
max(0, min(line_y, y + l) - y) * l - 上方面积:
max(0, y + l - max(line_y, y)) * l
算法步骤:
- 收集所有正方形的 y 坐标边界点
- 对边界点排序去重
- 使用二分搜索在边界点间寻找平衡点
- 计算总面积并验证上下平衡条件
时间复杂度主要来自二分搜索和面积计算,空间复杂度用于存储边界点。
代码实现
class Solution {
public:
double separateSquares(vector<vector<int>>& squares) {
vector<long long> points;
long long totalArea = 0;
for (auto& square : squares) {
long long x = square[0], y = square[1], l = square[2];
points.push_back(y);
points.push_back(y + l);
totalArea += l * l;
}
sort(points.begin(), points.end());
points.erase(unique(points.begin(), points.end()), points.end());
auto calculateBelow = [&](double lineY) -> double {
double below = 0;
for (auto& square : squares) {
long long x = square[0], y = square[1], l = square[2];
double overlap = max(0.0, min(lineY, (double)(y + l)) - y);
below += overlap * l;
}
return below;
};
double left = points[0], right = points.back();
double target = totalArea / 2.0;
for (int iter = 0; iter < 100; iter++) {
double mid = (left + right) / 2;
double belowArea = calculateBelow(mid);
if (belowArea < target) {
left = mid;
} else {
right = mid;
}
}
return (left + right) / 2;
}
};
class Solution:
def separateSquares(self, squares: List[List[int]]) -> float:
points = []
total_area = 0
for x, y, l in squares:
points.extend([y, y + l])
total_area += l * l
points = sorted(set(points))
def calculate_below(line_y):
below = 0
for x, y, l in squares:
overlap = max(0, min(line_y, y + l) - y)
below += overlap * l
return below
left, right = points[0], points[-1]
target = total_area / 2.0
for _ in range(100):
mid = (left + right) / 2
below_area = calculate_below(mid)
if below_area < target:
left = mid
else:
right = mid
return (left + right) / 2
public class Solution {
public double SeparateSquares(int[][] squares) {
var points = new List<long>();
long totalArea = 0;
foreach (var square in squares) {
long x = square[0], y = square[1], l = square[2];
points.Add(y);
points.Add(y + l);
totalArea += l * l;
}
points = points.Distinct().OrderBy(p => p).ToList();
double CalculateBelow(double lineY) {
double below = 0;
foreach (var square in squares) {
long x = square[0], y = square[1], l = square[2];
double overlap = Math.Max(0, Math.Min(lineY, y + l) - y);
below += overlap * l;
}
return below;
}
double left = points[0], right = points[points.Count - 1];
double target = totalArea / 2.0;
for (int iter = 0; iter < 100; iter++) {
double mid = (left + right) / 2;
double belowArea = CalculateBelow(mid);
if (belowArea < target) {
left = mid;
} else {
right = mid;
}
}
return (left + right) / 2;
}
}
var separateSquares = function(squares) {
const points = [];
let totalArea = 0;
for (const [x, y, l] of squares) {
points.push(y, y + l);
totalArea += l * l;
}
const uniquePoints = [...new Set(points)].sort((a, b) => a - b);
const calculateBelow = (lineY) => {
let below = 0;
for (const [x, y, l] of squares) {
const overlap = Math.max(0, Math.min(lineY, y + l) - y);
below += overlap * l;
}
return below;
};
let left = uniquePoints[0];
let right = uniquePoints[uniquePoints.length - 1];
const target = totalArea / 2.0;
for (let iter = 0; iter < 100; iter++) {
const mid = (left + right) / 2;
const belowArea = calculateBelow(mid);
if (belowArea < target) {
left = mid;
} else {
right = mid;
}
}
return (left + right) / 2;
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n log n + n log(max_coord)) | 排序 O(n log n),二分搜索进行 log(max_coord) 次迭代,每次计算面积 O(n) |
| 空间复杂度 | O(n) | 存储边界点数组 |