@@ -79,32 +79,276 @@ tags:
7979
8080<!-- solution:start -->
8181
82- ### 方法一
82+ ### 方法一:哈希表 + 枚举
83+
84+ 我们可以把所有点两两组合,计算出每一对点所对应的直线的斜率和截距,并使用哈希表进行记录,计算斜率相同且截距不同的直线两两组合得到的数量之和。注意,对于平行四边形,我们在上述计算中会被重复计算两次,因此我们需要将其减去。
85+
86+ 平行四边形的对角线中点重合,因此我们同样把所有点两两组合,计算出每一对点的中点坐标和斜率,并使用哈希表进行记录,计算斜率相同且中点坐标相同的点对两两组合得到的数量之和。
87+
88+ 具体地,我们使用两个哈希表 $\textit{cnt1}$ 和 $\textit{cnt2}$ 分别记录以下信息:
89+
90+ - 其中 $\textit{cnt1}$ 记录斜率 $k$ 和截距 $b$ 出现的次数,键为斜率 $k$,值为另一个哈希表,记录截距 $b$ 出现的次数;
91+ - 其中 $\textit{cnt2}$ 记录点对的中点坐标和斜率 $k$ 出现的次数,键为点对的中点坐标 $p$,值为另一个哈希表,记录斜率 $k$ 出现的次数。
92+
93+ 对于点对 $(x_1, y_1)$ 和 $(x_2, y_2)$,我们记 $dx = x_2 - x_1$,并且 $dy = y_2 - y_1$。如果 $dx = 0$,则说明两点在同一条垂直线上,我们记斜率 $k = +\infty$,截距 $b = x_1$;否则斜率 $k = \frac{dy}{dx}$,截距 $b = \frac{y_1 \cdot dx - x_1 \cdot dy}{dx}$。点对的中点坐标 $p$ 可以表示为 $p = (x_1 + x_2 + 2000) \cdot 4000 + (y_1 + y_2 + 2000)$,这里加上偏移量是为了避免负数。
94+
95+ 接下来,我们遍历所有点对,计算出对应的斜率 $k$、截距 $b$ 和中点坐标 $p$,并更新哈希表 $\textit{cnt1}$ 和 $\textit{cnt2}$。
96+
97+ 然后,我们遍历哈希表 $\textit{cnt1}$,对于每一个斜率 $k$,我们计算所有截距 $b$ 出现次数的两两组合之和,并累加到答案中。最后,我们遍历哈希表 $\textit{cnt2}$,对于每一个中点坐标 $p$,我们计算所有斜率 $k$ 出现次数的两两组合之和,并从答案中减去。
98+
99+ 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 是点的数量。
83100
84101<!-- tabs:start -->
85102
86103#### Python3
87104
88105``` python
89-
106+ class Solution :
107+ def countTrapezoids (self , points : List[List[int ]]) -> int :
108+ n = len (points)
109+
110+ # cnt1: k -> (b -> count)
111+ cnt1: dict[float , dict[float , int ]] = defaultdict(lambda : defaultdict(int ))
112+ # cnt2: p -> (k -> count)
113+ cnt2: dict[int , dict[float , int ]] = defaultdict(lambda : defaultdict(int ))
114+
115+ for i in range (n):
116+ x1, y1 = points[i]
117+ for j in range (i):
118+ x2, y2 = points[j]
119+ dx, dy = x2 - x1, y2 - y1
120+
121+ if dx == 0 :
122+ k = 1e9
123+ b = x1
124+ else :
125+ k = dy / dx
126+ b = (y1 * dx - x1 * dy) / dx
127+
128+ cnt1[k][b] += 1
129+
130+ p = (x1 + x2 + 2000 ) * 4000 + (y1 + y2 + 2000 )
131+ cnt2[p][k] += 1
132+
133+ ans = 0
134+
135+ for e in cnt1.values():
136+ s = 0
137+ for t in e.values():
138+ ans += s * t
139+ s += t
140+
141+ for e in cnt2.values():
142+ s = 0
143+ for t in e.values():
144+ ans -= s * t
145+ s += t
146+
147+ return ans
90148```
91149
92150#### Java
93151
94152``` java
95-
153+ class Solution {
154+ public int countTrapezoids (int [][] points ) {
155+ int n = points. length;
156+ Map<Double , Map<Double , Integer > > cnt1 = new HashMap<> (n * n);
157+ Map<Integer , Map<Double , Integer > > cnt2 = new HashMap<> (n * n);
158+
159+ for (int i = 0 ; i < n; ++ i) {
160+ int x1 = points[i][0 ], y1 = points[i][1 ];
161+ for (int j = 0 ; j < i; ++ j) {
162+ int x2 = points[j][0 ], y2 = points[j][1 ];
163+ int dx = x2 - x1, dy = y2 - y1;
164+ double k = dx == 0 ? Double . MAX_VALUE : 1.0 * dy / dx;
165+ double b = dx == 0 ? x1 : 1.0 * (y1 * dx - x1 * dy) / dx;
166+ if (k == - 0.0 ) {
167+ k = 0.0 ;
168+ }
169+ if (b == - 0.0 ) {
170+ b = 0.0 ;
171+ }
172+ cnt1. computeIfAbsent(k, _ - > new HashMap<> ()). merge(b, 1 , Integer :: sum);
173+ int p = (x1 + x2 + 2000 ) * 4000 + (y1 + y2 + 2000 );
174+ cnt2. computeIfAbsent(p, _ - > new HashMap<> ()). merge(k, 1 , Integer :: sum);
175+ }
176+ }
177+
178+ int ans = 0 ;
179+ for (var e : cnt1. values()) {
180+ int s = 0 ;
181+ for (int t : e. values()) {
182+ ans += s * t;
183+ s += t;
184+ }
185+ }
186+ for (var e : cnt2. values()) {
187+ int s = 0 ;
188+ for (int t : e. values()) {
189+ ans -= s * t;
190+ s += t;
191+ }
192+ }
193+ return ans;
194+ }
195+ }
96196```
97197
98198#### C++
99199
100200``` cpp
101-
201+ class Solution {
202+ public:
203+ int countTrapezoids(vector<vector<int >>& points) {
204+ int n = points.size();
205+ unordered_map<double, unordered_map<double, int>> cnt1;
206+ unordered_map<int, unordered_map<double, int>> cnt2;
207+
208+ cnt1.reserve(n * n);
209+ cnt2.reserve(n * n);
210+
211+ for (int i = 0; i < n; ++i) {
212+ int x1 = points[i][0], y1 = points[i][1];
213+ for (int j = 0; j < i; ++j) {
214+ int x2 = points[j][0], y2 = points[j][1];
215+ int dx = x2 - x1, dy = y2 - y1;
216+ double k = (dx == 0 ? 1e9 : 1.0 * dy / dx);
217+ double b = (dx == 0 ? x1 : 1.0 * (1LL * y1 * dx - 1LL * x1 * dy) / dx);
218+
219+ cnt1[k][b] += 1;
220+ int p = (x1 + x2 + 2000) * 4000 + (y1 + y2 + 2000);
221+ cnt2[p][k] += 1;
222+ }
223+ }
224+
225+ int ans = 0 ;
226+ for (auto & [_, e] : cnt1) {
227+ int s = 0;
228+ for (auto& [_, t] : e) {
229+ ans += s * t;
230+ s += t;
231+ }
232+ }
233+ for (auto& [_, e] : cnt2) {
234+ int s = 0;
235+ for (auto& [_, t] : e) {
236+ ans -= s * t;
237+ s += t;
238+ }
239+ }
240+ return ans;
241+ }
242+ };
102243```
103244
104245#### Go
105246
106247``` go
248+ func countTrapezoids (points [][]int ) int {
249+ n := len (points)
250+ cnt1 := make (map [float64 ]map [float64 ]int , n*n)
251+ cnt2 := make (map [int ]map [float64 ]int , n*n)
252+
253+ for i := 0 ; i < n; i++ {
254+ x1 , y1 := points[i][0 ], points[i][1 ]
255+ for j := 0 ; j < i; j++ {
256+ x2 , y2 := points[j][0 ], points[j][1 ]
257+ dx , dy := x2-x1, y2-y1
258+
259+ var k , b float64
260+ if dx == 0 {
261+ k = 1e9
262+ b = float64 (x1)
263+ } else {
264+ k = float64 (dy) / float64 (dx)
265+ b = float64 (int64 (y1)*int64 (dx)-int64 (x1)*int64 (dy)) / float64 (dx)
266+ }
267+
268+ if cnt1[k] == nil {
269+ cnt1[k] = make (map [float64 ]int )
270+ }
271+ cnt1[k][b]++
272+
273+ p := (x1+x2+2000 )*4000 + (y1 + y2 + 2000 )
274+ if cnt2[p] == nil {
275+ cnt2[p] = make (map [float64 ]int )
276+ }
277+ cnt2[p][k]++
278+ }
279+ }
280+
281+ ans := 0
282+ for _ , e := range cnt1 {
283+ s := 0
284+ for _ , t := range e {
285+ ans += s * t
286+ s += t
287+ }
288+ }
289+ for _ , e := range cnt2 {
290+ s := 0
291+ for _ , t := range e {
292+ ans -= s * t
293+ s += t
294+ }
295+ }
296+ return ans
297+ }
298+ ```
107299
300+ #### TypeScript
301+
302+ ``` ts
303+ function countTrapezoids(points : number [][]): number {
304+ const n = points .length ;
305+
306+ const cnt1: Map <number , Map <number , number >> = new Map ();
307+ const cnt2: Map <number , Map <number , number >> = new Map ();
308+
309+ for (let i = 0 ; i < n ; i ++ ) {
310+ const [x1, y1] = points [i ];
311+ for (let j = 0 ; j < i ; j ++ ) {
312+ const [x2, y2] = points [j ];
313+ const [dx, dy] = [x2 - x1 , y2 - y1 ];
314+
315+ const k = dx === 0 ? 1e9 : dy / dx ;
316+ const b = dx === 0 ? x1 : (y1 * dx - x1 * dy ) / dx ;
317+
318+ if (! cnt1 .has (k )) {
319+ cnt1 .set (k , new Map ());
320+ }
321+ const mapB = cnt1 .get (k )! ;
322+ mapB .set (b , (mapB .get (b ) || 0 ) + 1 );
323+
324+ const p = (x1 + x2 + 2000 ) * 4000 + (y1 + y2 + 2000 );
325+
326+ if (! cnt2 .has (p )) {
327+ cnt2 .set (p , new Map ());
328+ }
329+ const mapK = cnt2 .get (p )! ;
330+ mapK .set (k , (mapK .get (k ) || 0 ) + 1 );
331+ }
332+ }
333+
334+ let ans = 0 ;
335+ for (const e of cnt1 .values ()) {
336+ let s = 0 ;
337+ for (const t of e .values ()) {
338+ ans += s * t ;
339+ s += t ;
340+ }
341+ }
342+ for (const e of cnt2 .values ()) {
343+ let s = 0 ;
344+ for (const t of e .values ()) {
345+ ans -= s * t ;
346+ s += t ;
347+ }
348+ }
349+
350+ return ans ;
351+ }
108352```
109353
110354<!-- tabs:end -->
0 commit comments