Skip to content

Commit 74bb5de

Browse files
authored
feat: add solutions to lc problem: No.1577 (doocs#3887)
No.1577.Number of Ways Where Square of Number Is Equal to Product of Two Numbers
1 parent d02155a commit 74bb5de

File tree

12 files changed

+724
-221
lines changed

12 files changed

+724
-221
lines changed

solution/1500-1599/1577.Number of Ways Where Square of Number Is Equal to Product of Two Numbers/README.md

Lines changed: 241 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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
97244
class 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
122264
class 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

Comments
 (0)