https://leetcode.cn/problems/xepqZ5/
, @MARK_2
由于只有 N = 100 N=100 N=100的矩阵, 可以直接暴力枚举; 即我们考虑, 被重叠次数最多的这个矩阵T (他可能是一条线 或一个点, 都认为是矩阵), 有什么性质;
-{ 错误思路
这个矩阵T的顶点, 至少有1个 是原矩阵的顶点; (即原矩阵共 N ∗ 4 N*4 N∗4个顶点, 其中就是T的顶点);
这是错误的, 仅用3个矩阵 就可以构成一个重叠了3次的矩阵区域, 该区域的4个顶点 都不是原矩阵的顶点;
-}
矩阵T的4条边, 一定都是原矩阵的边;
.
设矩阵的左边为
L
L
L, 上边为
U
U
U, 左上角为
L
U
LU
LU (即
L
,
U
L,U
L,U的交点); 那么,
L
L
L一定来自于原矩阵的某个竖边,
U
U
U一定来自原矩阵的某个横边;
.
也就是, 矩阵T的4个顶点 一定是原矩阵的某个横边与某个竖边的交点; 因此, 我们枚举原矩阵的所有交点, 其实一定含有 答案矩阵T的顶点;
因此, 枚举原矩阵的所有竖边
A
A
A (
2
N
2N
2N个), 再枚举原矩阵的所有横边
B
B
B (
2
N
2N
2N个);
.
判断如果
A
,
B
A,B
A,B并不相交, 则continue
; (这是个优化, 会大大提升时间);
.
得到
A
,
B
A,B
A,B的交点
C
C
C, 再
O
(
N
)
O(N)
O(N)遍历所有矩阵 看有多少矩阵包含了该点
C
C
C;
该算法是 O ( N 3 ) O(N^3) O(N3)的;
-{ 这里提一个技巧; @MARK_0
;
原矩阵的四个顶点, 他的坐标会是浮点数, 因为 ( x ± d / 2 , y ± d / 2 ) (x \pm d/2, y \pm d/2) (x±d/2,y±d/2), 当 d d d为奇数, 那么 d / 2 d/2 d/2就是个浮点数;
我们会涉及到大量的比较操作, 浮点数的比较 (虽然这道题你直接使用a<=b
是没问题的) 通过要考虑精度问题, 能避开浮点数最好避开;
我们对整个坐标系 (以原点为中心) 放大1倍后, 不会影响答案 (原来答案区域面积为S, 现在会变成
4
S
4S
4S), 答案矩阵的顶点 依然是原矩阵的交点;
.
原来是(x, y, d)
(正方形的中心点在(x,y)
, 边长为d
), 现在是(2x, 2y, 2d)
;
-}
@DELIMITER
这里再介绍一种算法, 他是
O
(
N
2
)
O(N^2)
O(N2)的; @MARK_1
;
本质上他也是基于上面的结论; 对每个矩阵, 把他的4条边 无限的延伸下去 形成网格线, 最终, 这个坐标系 就变成了网格, 那么有多少个网格点呢 (网格点: 即2条网格线的交点), 最多有 2 N ∗ 2 N 2N * 2N 2N∗2N个;
此时答案矩阵, 他的顶点 一定是网格点; (这个是上面分析过的)
.
但要注意, 他的内部 也可能有网格点; 假如该矩阵被覆盖了K次, 那么, 对于任意在该矩阵上的网格点 (可能在内部, 也可以在边上), 每个网格点 都是被覆盖了K次;
但是, 由于这些网格点 坐标是(-3e9, 3e9)
(坐标系放大1倍后), 我们对他进行二维离散化, 即这些网格点, 都变成了( {0,...,200}, {0, 200})
的范围;
.
然后, 对于一个矩阵 他所覆盖的网格点 对应离散化以后 一定是一个连续的 (比如他覆盖的网格点是(1,1) (1,2) (1,3) (2,1) (2,2) (2,3)
), 因此进行2D的差分操作, 将该矩阵所覆盖的网格点 都+= 1
;
.
最后, 枚举所有的网格点, 求他的覆盖次数;
int fieldOfGreatestBlessing(vector<vector<int>>& F) {
int n = F.size();
__HashDiscretization< long long> H( 2 * n), V( 2 * n);
for( int i = 0; i < n; ++i){
auto l = (long long)F[ i][ 0] * 2 - F[ i][ 2];
auto r = (long long)F[ i][ 0] * 2 + F[ i][ 2];
auto d = (long long)F[ i][ 1] * 2 - F[ i][ 2];
auto u = (long long)F[ i][ 1] * 2 + F[ i][ 2];
H.Add( l), H.Add( r), V.Add( d), V.Add( u);
}
H.Discretize(), V.Discretize();
__DifferentialArray_2D< int, 205> D( H.Get_size(), H.Get_size(), V.Get_size());
//< 注意, 第一参数是`H.size`, 不是`V.size`; `205`是指的Y (即第2维度)的大小, 第1维度的大小 是用户指定的;
for( auto & i : F){
long long dx = i[0] * 2, dy = i[1] * 2, dd = i[2];
auto l = dx - dd, r = dx + dd, u = dy + dd , d = dy - dd;
l = H.Get_hash( l), r = H.Get_hash( r);
u = V.Get_hash( u), d = V.Get_hash( d);
D.Add_area( l, d, r, u, 1);
}
D.Restore();
int Ans = 0;
for( int i = 0; i < (int)H.Get_size(); ++i){
for( int j = 0; j < (int)V.Get_size(); ++j){
Ans = max( Ans, D.Get_restoredValue( i, j));
}
}
return Ans;
}