Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 74bb5de

Browse files
feat: add solutions to lc problem: No.1577 (#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)

AltStyle によって変換されたページ (->オリジナル) /