@@ -76,18 +76,165 @@ tags:
7676
7777<!-- solution:start -->
7878
79- ### 方法一:哈希表
79+ ### 方法一:哈希表 + 枚举
8080
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}$ 的长度 。
8282
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$,最后将两者相加返回即可。
8484
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}$ 的长度。
8786
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+ ```
89141
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}$ 的长度。
91238
92239<!-- tabs:start -->
93240
@@ -96,95 +243,83 @@ tags:
96243``` python
97244class Solution :
98245 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+
99256 cnt1 = Counter(nums1)
100257 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)
117259```
118260
119261#### Java
120262
121263``` java
122264class Solution {
123265 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);
131275 }
276+ return cnt;
277+ }
278+
279+ private int cal (Map<Integer , Integer > cnt , int [] nums ) {
132280 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);
152288 }
153289 }
154290 }
155- return (int ) (ans >> 1 );
291+ return (int ) (ans / 2 );
156292 }
157293}
158294```
159295
160296#### Go
161297
162298``` 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]++
171309 }
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
188323 }
189324 }
190325 }
@@ -194,6 +329,38 @@ func numTriplets(nums1 []int, nums2 []int) (ans int) {
194329}
195330```
196331
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+
197364<!-- tabs:end -->
198365
199366<!-- solution:end -->
0 commit comments