小扣在探索丛林的过程中,无意间发现了传说中“落寞的黄金之都”。而在这片建筑废墟的地带中,小扣使用探测仪监测到了存在某种带有「祝福」效果的力场。 经过不断的勘测记录,小扣将所有力场的分布都记录了下来。forceField[i] = [x,y,side]
表示第 i
片力场将覆盖以坐标 (x,y)
为中心,边长为 side
的正方形区域。
若任意一点的 力场强度 等于覆盖该点的力场数量,请求出在这片地带中 力场强度 最强处的 力场强度。
注意:
- 力场范围的边缘同样被力场覆盖。
示例 1:
输入:
forceField = [[0,0,1],[1,0,1]]
输出:
2
解释:如图所示,(0.5, 0) 处力场强度最强为 2, (0.5,-0.5)处力场强度同样是 2。
示例 2:
输入:
forceField = [[4,4,6],[7,5,3],[1,6,2],[5,6,3]]
输出:
3
解释:如下图所示,
forceField[0]、forceField[1]、forceField[3]
重叠的区域力场强度最大,返回3
提示:
1 <= forceField.length <= 100
forceField[i].length == 3
0 <= forceField[i][0], forceField[i][1] <= 10^9
1 <= forceField[i][2] <= 10^9
解法1:离散化 + 二维差分 + 二维前缀和
思路
- 统计所有左下和右上坐标,由于会出现 0.5,可以将坐标乘 2。
- 离散化横纵坐标。
- 二维差分。
- 用二维前缀和复原,计算最大值。
Java版:
class Solution {
public int fieldOfGreatestBlessing(int[][] forceField) {
Set<Long> x_set = new HashSet<>();
Set<Long> y_set = new HashSet<>();
// 1. 统计所有左下和右上坐标
for (int[] f: forceField) {
x_set.add((long) 2 * f[0] - f[2]);
x_set.add((long) 2 * f[0] + f[2]);
y_set.add((long) 2 * f[1] - f[2]);
y_set.add((long) 2 * f[1] + f[2]);
}
// 2. 排序
long[] xs = x_set.stream().mapToLong(Long::longValue).toArray();
long[] ys = y_set.stream().mapToLong(Long::longValue).toArray();
Arrays.sort(xs);
Arrays.sort(ys);
int m = ys.length;
int n = xs.length;
int[][] diff = new int[m + 2][n + 2];
// 3. 二维差分
for (int[] f: forceField) {
long x = f[0];
long y = f[1];
long side = f[2];
int c1 = Arrays.binarySearch(xs, 2 * x - side);
int c2 = Arrays.binarySearch(xs, 2 * x + side);
int r1 = Arrays.binarySearch(ys, 2 * y - side);
int r2 = Arrays.binarySearch(ys, 2 * y + side);
diff[r1 + 1][c1 + 1]++;
diff[r1 + 1][c2 + 2]--;
diff[r2 + 2][c1 + 1]--;
diff[r2 + 2][c2 + 2]++;
}
// 4. 直接在 diff 上复原,计算最大值
int ans = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
diff[i][j] += diff[i][j - 1] + diff[i - 1][j] - diff[i - 1][j - 1];
ans = Math.max(ans, diff[i][j]);
}
}
return ans;
}
}
Python3版:
二分查找 前提:列表有序!!!
bisect.bisect和bisect.bisect_right返回大于x的第一个下标(相当于C++中的upper_bound),bisect.bisect_left返回大于等于x的第一个下标(相当于C++中的lower_bound)。
class Solution:
def fieldOfGreatestBlessing(self, forceField: List[List[int]]) -> int:
x_set = set()
y_set = set()
for x, y, side in forceField:
x_set.add(2 * x - side)
x_set.add(2 * x + side)
y_set.add(2 * y - side)
y_set.add(2 * y + side)
xs = sorted(x_set)
ys = sorted(y_set)
m = len(ys)
n = len(xs)
diff = [[0] * (n + 2) for _ in range(m + 2)]
for x, y, side in forceField:
c1 = bisect_left(xs, 2 * x - side)
c2 = bisect_left(xs, 2 * x + side)
r1 = bisect_left(ys, 2 * y - side)
r2 = bisect_left(ys, 2 * y + side)
diff[r1 + 1][c1 + 1] += 1
diff[r1 + 1][c2 + 2] -= 1
diff[r2 + 2][c1 + 1] -= 1
diff[r2 + 2][c2 + 2] += 1
ans = 0
for i in range(1, m + 1):
for j in range(1, n + 1):
diff[i][j] += diff[i][j - 1] + diff[i - 1][j] - diff[i - 1][j - 1]
ans = max(ans, diff[i][j])
return ans
复杂度分析
- 时间复杂度:O(n^2),其中 n 为 forceField 的长度。
- 空间复杂度:O(n^2)。