@@ -76,18 +76,165 @@ tags:
76
76
77
77
<!-- solution:start -->
78
78
79
- ### 方法一:哈希表
79
+ ### 方法一:哈希表 + 枚举
80
80
81
- 我们用哈希表 ` cnt1 ` 统计 ` nums1 ` 中每个数出现的次数, 用哈希表 ` cnt2 ` 统计 ` nums2 ` 中每个数出现的次数 。
81
+ 我们用哈希表 $\textit{ cnt1}$ 统计 $\textit{ nums1}$ 中每个数对 $(\textit{nums} [ j ] , \textit{nums} [ k ] )$ 出现的次数,其中 $0 \leq j \lt k < m$,其中 $m$ 为数组 $\textit{nums1}$ 的长度。 用哈希表 $\textit{ cnt2}$ 统计 $\textit{ nums2}$ 中每个数对 $(\textit{nums} [ j ] , \textit{nums} [ k ] )$ 出现的次数,其中 $0 \leq j \lt k < n$,其中 $n$ 为数组 $\textit{nums2}$ 的长度 。
82
82
83
- 然后我们双重循环遍历两个哈希表,记当前 ` cnt1 ` 遍历到的键值对为 $(a, x)$,当前 ` cnt2 ` 遍历到的键值对为 $(b, y)$。接下来分情况讨论:
83
+ 接下来,我们枚举数组 $\textit{nums1}$ 中的每个数 $x$,计算 $\textit{cnt2} [ x^2 ] $ 的值,即 $\textit{nums2}$ 中有多少对数 $(\textit{nums} [ j ] , \textit{nums} [ k ] )$ 满足 $\textit{nums} [ j ] \times \textit{nums} [ k ] = x^2$。同理,我们枚举数组 $\textit{nums2}$ 中的每个数 $x$,计算 $\textit{cnt1} [ x^2 ] $ 的值,即 $\textit{nums1}$ 中有多少对数 $(\textit{nums} [ j ] , \textit{nums} [ k ] )$ 满足 $\textit{nums} [ j ] \times \textit{nums} [ k ] = x^2$,最后将两者相加返回即可。
84
84
85
- - 如果 $a^2$ 能被 $b$ 整除,设 $c=\frac{a^2}{b}$,若 $b=c$,那么答案加上 $x \times y \times (y - 1)$,否则答案加上 $x \times y \times cnt2[ c] $。
86
- - 如果 $b^2$ 能被 $a$ 整除,设 $c=\frac{b^2}{a}$,若 $a=c$,那么答案加上 $x \times (x - 1) \times y$,否则答案加上 $x \times cnt1[ c] \times y$。
85
+ 时间复杂度 $O(m^2 + n^2 + m + n)$,空间复杂度 $O(m^2 + n^2)$。其中 $m$ 和 $n$ 分别为数组 $\textit{nums1}$ 和 $\textit{nums2}$ 的长度。
87
86
88
- 最后将答案除以 $2$ 返回即可。
87
+ <!-- tabs:start -->
88
+
89
+ #### Python3
90
+
91
+ ``` python
92
+ class Solution :
93
+ def numTriplets (self , nums1 : List[int ], nums2 : List[int ]) -> int :
94
+ def count (nums : List[int ]) -> Counter:
95
+ cnt = Counter()
96
+ for j in range (len (nums)):
97
+ for k in range (j + 1 , len (nums)):
98
+ cnt[nums[j] * nums[k]] += 1
99
+ return cnt
100
+
101
+ def cal (nums : List[int ], cnt : Counter) -> int :
102
+ return sum (cnt[x * x] for x in nums)
103
+
104
+ cnt1 = count(nums1)
105
+ cnt2 = count(nums2)
106
+ return cal(nums1, cnt2) + cal(nums2, cnt1)
107
+ ```
108
+
109
+ #### Java
110
+
111
+ ``` java
112
+ class Solution {
113
+ public int numTriplets (int [] nums1 , int [] nums2 ) {
114
+ var cnt1 = count(nums1);
115
+ var cnt2 = count(nums2);
116
+ return cal(cnt1, nums2) + cal(cnt2, nums1);
117
+ }
118
+
119
+ private Map<Long , Integer > count (int [] nums ) {
120
+ Map<Long , Integer > cnt = new HashMap<> ();
121
+ int n = nums. length;
122
+ for (int j = 0 ; j < n; ++ j) {
123
+ for (int k = j + 1 ; k < n; ++ k) {
124
+ long x = (long ) nums[j] * nums[k];
125
+ cnt. merge(x, 1 , Integer :: sum);
126
+ }
127
+ }
128
+ return cnt;
129
+ }
130
+
131
+ private int cal (Map<Long , Integer > cnt , int [] nums ) {
132
+ int ans = 0 ;
133
+ for (int x : nums) {
134
+ long y = (long ) x * x;
135
+ ans += cnt. getOrDefault(y, 0 );
136
+ }
137
+ return ans;
138
+ }
139
+ }
140
+ ```
89
141
90
- 时间复杂度 $O(n \times m)$,空间复杂度 $O(n + m)$。其中 $n$ 和 $m$ 分别为数组 ` nums1 ` 和 ` nums2 ` 的长度。
142
+ #### C++
143
+
144
+ ``` cpp
145
+ class Solution {
146
+ public:
147
+ int numTriplets(vector<int >& nums1, vector<int >& nums2) {
148
+ auto cnt1 = count(nums1);
149
+ auto cnt2 = count(nums2);
150
+ return cal(cnt1, nums2) + cal(cnt2, nums1);
151
+ }
152
+
153
+ unordered_map<long long, int> count(vector<int>& nums) {
154
+ unordered_map<long long, int> cnt;
155
+ for (int i = 0; i < nums.size(); i++) {
156
+ for (int j = i + 1; j < nums.size(); j++) {
157
+ cnt[(long long) nums[i] * nums[j]]++;
158
+ }
159
+ }
160
+ return cnt;
161
+ }
162
+
163
+ int cal (unordered_map<long long, int>& cnt, vector<int >& nums) {
164
+ int ans = 0;
165
+ for (int x : nums) {
166
+ ans += cnt[ (long long) x * x] ;
167
+ }
168
+ return ans;
169
+ }
170
+ };
171
+ ```
172
+
173
+ #### Go
174
+
175
+ ```go
176
+ func numTriplets(nums1 []int, nums2 []int) int {
177
+ cnt1 := count(nums1)
178
+ cnt2 := count(nums2)
179
+ return cal(cnt1, nums2) + cal(cnt2, nums1)
180
+ }
181
+
182
+ func count(nums []int) map[int]int {
183
+ cnt := map[int]int{}
184
+ for j, x := range nums {
185
+ for _, y := range nums[j+1:] {
186
+ cnt[x*y]++
187
+ }
188
+ }
189
+ return cnt
190
+ }
191
+
192
+ func cal(cnt map[int]int, nums []int) (ans int) {
193
+ for _, x := range nums {
194
+ ans += cnt[x*x]
195
+ }
196
+ return
197
+ }
198
+ ```
199
+
200
+ #### TypeScript
201
+
202
+ ``` ts
203
+ function numTriplets(nums1 : number [], nums2 : number []): number {
204
+ const cnt1 = count (nums1 );
205
+ const cnt2 = count (nums2 );
206
+ return cal (cnt1 , nums2 ) + cal (cnt2 , nums1 );
207
+ }
208
+
209
+ function count(nums : number []): Map <number , number > {
210
+ const cnt: Map <number , number > = new Map ();
211
+ for (let j = 0 ; j < nums .length ; ++ j ) {
212
+ for (let k = j + 1 ; k < nums .length ; ++ k ) {
213
+ const x = nums [j ] * nums [k ];
214
+ cnt .set (x , (cnt .get (x ) || 0 ) + 1 );
215
+ }
216
+ }
217
+ return cnt ;
218
+ }
219
+
220
+ function cal(cnt : Map <number , number >, nums : number []): number {
221
+ return nums .reduce ((acc , x ) => acc + (cnt .get (x * x ) || 0 ), 0 );
222
+ }
223
+ ```
224
+
225
+ <!-- tabs:end -->
226
+
227
+ <!-- solution:end -->
228
+
229
+ <!-- solution:start -->
230
+
231
+ ### 方法二:哈希表 + 枚举优化
232
+
233
+ 我们用哈希表 $\textit{cnt1}$ 统计 $\textit{nums1}$ 中每个数出现的次数,用哈希表 $\textit{cnt2}$ 统计 $\textit{nums2}$ 中每个数出现的次数。
234
+
235
+ 接下来,我们枚举数组 $\textit{nums1}$ 中的每个数 $x$,然后枚举 $\textit{cnt2}$ 中的每个数对 $(y, v1)$,其中 $y$ 为 $\textit{cnt2}$ 的键,$v1$ 为 $\textit{cnt2}$ 的值。我们计算 $z = x^2 / y$,如果 $y \times z = x^2$,此时如果 $y = z$,说明 $y$ 和 $z$ 是同一个数,那么 $v1 = v2$,从 $v1$ 个数中任选两个数的方案数为 $v1 \times (v1 - 1) = v1 \times (v2 - 1)$;如果 $y \neq z$,那么 $v1$ 个数中任选两个数的方案数为 $v1 \times v2$。最后将所有方案数相加并除以 $2$ 即可。这里除以 $2$ 是因为我们统计的是对数对 $(j, k)$ 的方案数,而实际上 $(j, k)$ 和 $(k, j)$ 是同一种方案。
236
+
237
+ 时间复杂度 $O(m \times n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为数组 $\textit{nums1}$ 和 $\textit{nums2}$ 的长度。
91
238
92
239
<!-- tabs:start -->
93
240
@@ -96,95 +243,83 @@ tags:
96
243
``` python
97
244
class Solution :
98
245
def numTriplets (self , nums1 : List[int ], nums2 : List[int ]) -> int :
246
+ def cal (nums : List[int ], cnt : Counter) -> int :
247
+ ans = 0
248
+ for x in nums:
249
+ for y, v1 in cnt.items():
250
+ z = x * x // y
251
+ if y * z == x * x:
252
+ v2 = cnt[z]
253
+ ans += v1 * (v2 - int (y == z))
254
+ return ans // 2
255
+
99
256
cnt1 = Counter(nums1)
100
257
cnt2 = Counter(nums2)
101
- ans = 0
102
- for a, x in cnt1.items():
103
- for b, y in cnt2.items():
104
- if a * a % b == 0 :
105
- c = a * a // b
106
- if b == c:
107
- ans += x * y * (y - 1 )
108
- else :
109
- ans += x * y * cnt2[c]
110
- if b * b % a == 0 :
111
- c = b * b // a
112
- if a == c:
113
- ans += x * (x - 1 ) * y
114
- else :
115
- ans += x * y * cnt1[c]
116
- return ans >> 1
258
+ return cal(nums1, cnt2) + cal(nums2, cnt1)
117
259
```
118
260
119
261
#### Java
120
262
121
263
``` java
122
264
class Solution {
123
265
public int numTriplets (int [] nums1 , int [] nums2 ) {
124
- Map<Integer , Integer > cnt1 = new HashMap<> ();
125
- Map<Integer , Integer > cnt2 = new HashMap<> ();
126
- for (int v : nums1) {
127
- cnt1. put(v, cnt1. getOrDefault(v, 0 ) + 1 );
128
- }
129
- for (int v : nums2) {
130
- cnt2. put(v, cnt2. getOrDefault(v, 0 ) + 1 );
266
+ var cnt1 = count(nums1);
267
+ var cnt2 = count(nums2);
268
+ return cal(cnt1, nums2) + cal(cnt2, nums1);
269
+ }
270
+
271
+ private Map<Integer , Integer > count (int [] nums ) {
272
+ Map<Integer , Integer > cnt = new HashMap<> ();
273
+ for (int x : nums) {
274
+ cnt. merge(x, 1 , Integer :: sum);
131
275
}
276
+ return cnt;
277
+ }
278
+
279
+ private int cal (Map<Integer , Integer > cnt , int [] nums ) {
132
280
long ans = 0 ;
133
- for (var e1 : cnt1. entrySet()) {
134
- long a = e1. getKey(), x = e1. getValue();
135
- for (var e2 : cnt2. entrySet()) {
136
- long b = e2. getKey(), y = e2. getValue();
137
- if ((a * a) % b == 0 ) {
138
- long c = a * a / b;
139
- if (b == c) {
140
- ans += x * y * (y - 1 );
141
- } else {
142
- ans += x * y * cnt2. getOrDefault((int ) c, 0 );
143
- }
144
- }
145
- if ((b * b) % a == 0 ) {
146
- long c = b * b / a;
147
- if (a == c) {
148
- ans += x * (x - 1 ) * y;
149
- } else {
150
- ans += x * y * cnt1. getOrDefault((int ) c, 0 );
151
- }
281
+ for (int x : nums) {
282
+ for (var e : cnt. entrySet()) {
283
+ int y = e. getKey(), v1 = e. getValue();
284
+ int z = (int ) (1L * x * x / y);
285
+ if (y * z == x * x) {
286
+ int v2 = cnt. getOrDefault(z, 0 );
287
+ ans += v1 * (y == z ? v2 - 1 : v2);
152
288
}
153
289
}
154
290
}
155
- return (int ) (ans >> 1 );
291
+ return (int ) (ans / 2 );
156
292
}
157
293
}
158
294
```
159
295
160
296
#### Go
161
297
162
298
``` go
163
- func numTriplets (nums1 []int , nums2 []int ) (ans int ) {
164
- cnt1 := map [int ]int {}
165
- cnt2 := map [int ]int {}
166
- for _ , v := range nums1 {
167
- cnt1[v]++
168
- }
169
- for _ , v := range nums2 {
170
- cnt2[v]++
299
+ func numTriplets (nums1 []int , nums2 []int ) int {
300
+ cnt1 := count (nums1)
301
+ cnt2 := count (nums2)
302
+ return cal (cnt1, nums2) + cal (cnt2, nums1)
303
+ }
304
+
305
+ func count (nums []int ) map [int ]int {
306
+ cnt := map [int ]int {}
307
+ for _ , x := range nums {
308
+ cnt[x]++
171
309
}
172
- for a , x := range cnt1 {
173
- for b , y := range cnt2 {
174
- if a*a%b == 0 {
175
- c := a * a / b
176
- if b == c {
177
- ans += x * y * (y - 1 )
178
- } else {
179
- ans += x * y * cnt2[c]
180
- }
181
- }
182
- if b*b%a == 0 {
183
- c := b * b / a
184
- if a == c {
185
- ans += x * (x - 1 ) * y
186
- } else {
187
- ans += x * y * cnt1[c]
310
+ return cnt
311
+ }
312
+
313
+ func cal (cnt map [int ]int , nums []int ) (ans int ) {
314
+ for _ , x := range nums {
315
+ for y , v1 := range cnt {
316
+ z := x * x / y
317
+ if y*z == x*x {
318
+ if v2 , ok := cnt[z]; ok {
319
+ if y == z {
320
+ v2--
321
+ }
322
+ ans += v1 * v2
188
323
}
189
324
}
190
325
}
@@ -194,6 +329,38 @@ func numTriplets(nums1 []int, nums2 []int) (ans int) {
194
329
}
195
330
```
196
331
332
+ #### TypeScript
333
+
334
+ ``` ts
335
+ function numTriplets(nums1 : number [], nums2 : number []): number {
336
+ const cnt1 = count (nums1 );
337
+ const cnt2 = count (nums2 );
338
+ return cal (cnt1 , nums2 ) + cal (cnt2 , nums1 );
339
+ }
340
+
341
+ function count(nums : number []): Map <number , number > {
342
+ const cnt: Map <number , number > = new Map ();
343
+ for (const x of nums ) {
344
+ cnt .set (x , (cnt .get (x ) || 0 ) + 1 );
345
+ }
346
+ return cnt ;
347
+ }
348
+
349
+ function cal(cnt : Map <number , number >, nums : number []): number {
350
+ let ans: number = 0 ;
351
+ for (const x of nums ) {
352
+ for (const [y, v1] of cnt ) {
353
+ const z = Math .floor ((x * x ) / y );
354
+ if (y * z == x * x ) {
355
+ const v2 = cnt .get (z ) || 0 ;
356
+ ans += v1 * (y === z ? v2 - 1 : v2 );
357
+ }
358
+ }
359
+ }
360
+ return ans / 2 ;
361
+ }
362
+ ```
363
+
197
364
<!-- tabs:end -->
198
365
199
366
<!-- solution:end -->
0 commit comments