题目
标题和出处
标题:数的平方等于两数乘积的方法数
难度
5 级
题目描述
要求
给你两个整数数组 nums1 \texttt{nums1} nums1 和 nums2 \texttt{nums2} nums2,请你返回根据以下规则形成的三元组的数目(类型 1 \texttt{1} 1 和类型 2 \texttt{2} 2):
- 类型 1 \texttt{1} 1:三元组 (i, j, k) \texttt{(i, j, k)} (i, j, k),如果 nums1[i] 2 = nums2[j] × nums2[k] \texttt{nums1[i]}^\texttt{2} = \texttt{nums2[j]} \times \texttt{nums2[k]} nums1[i]2=nums2[j]×nums2[k],其中 0 ≤ i < nums1.length \texttt{0} \le \texttt{i} < \texttt{nums1.length} 0≤i<nums1.length 且 0 ≤ j < k < nums2.length \texttt{0} \le \texttt{j} < \texttt{k} < \texttt{nums2.length} 0≤j<k<nums2.length。
- 类型 2 \texttt{2} 2:三元组 (i, j, k) \texttt{(i, j, k)} (i, j, k),如果 nums2[i] 2 = nums1[j] × nums1[k] \texttt{nums2[i]}^\texttt{2} = \texttt{nums1[j]} \times \texttt{nums1[k]} nums2[i]2=nums1[j]×nums1[k],其中 0 ≤ i < nums2.length \texttt{0} \le \texttt{i} < \texttt{nums2.length} 0≤i<nums2.length 且 0 ≤ j < k < nums1.length \texttt{0} \le \texttt{j} < \texttt{k} < \texttt{nums1.length} 0≤j<k<nums1.length。
示例
示例 1:
输入:
nums1
=
[7,4],
nums2
=
[5,2,8,9]
\texttt{nums1 = [7,4], nums2 = [5,2,8,9]}
nums1 = [7,4], nums2 = [5,2,8,9]
输出:
1
\texttt{1}
1
解释:类型
1
\texttt{1}
1:
(1,1,2)
\texttt{(1,1,2)}
(1,1,2),
nums1[1]
2
=
nums2[1]
×
nums2[2]
\texttt{nums1[1]}^\texttt{2} = \texttt{nums2[1]} \times \texttt{nums2[2]}
nums1[1]2=nums2[1]×nums2[2](
4
2
=
2
×
8
\texttt{4}^\texttt{2} = \texttt{2} \times \texttt{8}
42=2×8)。
示例 2:
输入:
nums1
=
[1,1],
nums2
=
[1,1,1]
\texttt{nums1 = [1,1], nums2 = [1,1,1]}
nums1 = [1,1], nums2 = [1,1,1]
输出:
9
\texttt{9}
9
解释:所有三元组都符合题目要求,因为
1
2
=
1
×
1
\texttt{1}^\texttt{2} = \texttt{1} \times \texttt{1}
12=1×1。
类型
1
\texttt{1}
1:
(0,0,1)
\texttt{(0,0,1)}
(0,0,1),
(0,0,2)
\texttt{(0,0,2)}
(0,0,2),
(0,1,2)
\texttt{(0,1,2)}
(0,1,2),
(1,0,1)
\texttt{(1,0,1)}
(1,0,1),
(1,0,2)
\texttt{(1,0,2)}
(1,0,2),
(1,1,2)
\texttt{(1,1,2)}
(1,1,2),
nums1[i]
2
=
nums2[j]
×
nums2[k]
\texttt{nums1[i]}^\texttt{2} = \texttt{nums2[j]} \times \texttt{nums2[k]}
nums1[i]2=nums2[j]×nums2[k]。
类型
2
\texttt{2}
2:
(0,0,1)
\texttt{(0,0,1)}
(0,0,1),
(1,0,1)
\texttt{(1,0,1)}
(1,0,1),
(2,0,1)
\texttt{(2,0,1)}
(2,0,1),
nums2[i]
2
=
nums1[j]
×
nums1[k]
\texttt{nums2[i]}^\texttt{2} = \texttt{nums1[j]} \times \texttt{nums1[k]}
nums2[i]2=nums1[j]×nums1[k]。
示例 3:
输入:
nums1
=
[7,7,8,3],
nums2
=
[1,2,9,7]
\texttt{nums1 = [7,7,8,3], nums2 = [1,2,9,7]}
nums1 = [7,7,8,3], nums2 = [1,2,9,7]
输出:
2
\texttt{2}
2
解释:有两个符合题目要求的三元组。
类型
1
\texttt{1}
1:
(3,0,2)
\texttt{(3,0,2)}
(3,0,2),
nums1[3]
2
=
nums2[0]
×
nums2[2]
\texttt{nums1[3]}^\texttt{2} = \texttt{nums2[0]} \times \texttt{nums2[2]}
nums1[3]2=nums2[0]×nums2[2]。
类型
2
\texttt{2}
2:
(3,0,1)
\texttt{(3,0,1)}
(3,0,1),
nums2[3]
2
=
nums1[0]
×
nums1[1]
\texttt{nums2[3]}^\texttt{2} = \texttt{nums1[0]} \times \texttt{nums1[1]}
nums2[3]2=nums1[0]×nums1[1]。
示例 4:
输入:
nums1
=
[4,7,9,11,23],
nums2
=
[3,5,1024,12,18]
\texttt{nums1 = [4,7,9,11,23], nums2 = [3,5,1024,12,18]}
nums1 = [4,7,9,11,23], nums2 = [3,5,1024,12,18]
输出:
0
\texttt{0}
0
解释:不存在符合题目要求的三元组。
数据范围
- 1 ≤ nums1.length, nums2.length ≤ 1000 \texttt{1} \le \texttt{nums1.length, nums2.length} \le \texttt{1000} 1≤nums1.length, nums2.length≤1000
- 1 ≤ nums1[i], nums2[i] ≤ 10 5 \texttt{1} \le \texttt{nums1[i], nums2[i]} \le \texttt{10}^\texttt{5} 1≤nums1[i], nums2[i]≤105
解法
思路和算法
用 ( i , j , k ) (i, j, k) (i,j,k) 表示符合题目要求的三元组。
如果 ( i , j , k ) (i, j, k) (i,j,k) 是类型 1 1 1 的三元组,则令 x = nums 1 [ i ] x = \textit{nums}_1[i] x=nums1[i], y = nums 2 [ j ] y = \textit{nums}_2[j] y=nums2[j], z = nums 2 [ k ] z = \textit{nums}_2[k] z=nums2[k],有 x 2 = y × z x^2 = y \times z x2=y×z。如果 ( i , j , k ) (i, j, k) (i,j,k) 是类型 2 2 2 的三元组,则令 x = nums 2 [ i ] x = \textit{nums}_2[i] x=nums2[i], y = nums 1 [ j ] y = \textit{nums}_1[j] y=nums1[j], z = nums 1 [ k ] z = \textit{nums}_1[k] z=nums1[k],有 x 2 = y × z x^2 = y \times z x2=y×z。
为了计算符合题目要求的三元组的数目,需要分别计算类型 1 1 1 和类型 2 2 2 的三元组的数目。假设数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度分别是 m m m 和 n n n。如果暴力统计符合题目要求的三元组,则统计类型 1 1 1 的三元组需要 O ( m n 2 ) O(mn^2) O(mn2) 的时间,统计类型 2 2 2 的三元组需要 O ( n m 2 ) O(nm^2) O(nm2) 的时间,总时间复杂度是 O ( m n ( m + n ) ) O(mn(m + n)) O(mn(m+n)),会超出时间限制,因此需要优化。
暴力方法的时间复杂度过高是因为相同的元素被重复计算。为了降低时间复杂度,应该避免重复计算。可以使用哈希表记录数组中的元素和每个元素的出现次数。
首先遍历数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2,分别用两个哈希表记录两个数组中每个元素的出现次数,用 set 1 \textit{set}_1 set1 和 set 2 \textit{set}_2 set2 分别表示两个数组的元素集合,然后计算两种类型的三元组的数目。两种类型的三元组的数目的计算方式大致相同。
计算类型 1 1 1 的三元组的数目的方法如下:对于集合 set 1 \textit{set}_1 set1 中的每个元素 x x x,遍历集合 set 2 \textit{set}_2 set2 中的每个元素 y y y,如果集合 set 2 \textit{set}_2 set2 中存在元素 z z z 满足 x 2 = y × z x^2 = y \times z x2=y×z 且 y y y 和 z z z 在数组 nums 2 \textit{nums}_2 nums2 中对应的下标不同,则 x x x、 y y y 和 z z z 这三个元素组成一个类型 1 1 1 的三元组。记 x x x 在数组 nums 1 \textit{nums}_1 nums1 中的出现次数为 xCount \textit{xCount} xCount, y y y 和 z z z 在数组 nums 2 \textit{nums}_2 nums2 中的出现次数分别为 yCount \textit{yCount} yCount 和 zCount \textit{zCount} zCount,则可以根据出现次数计算该三元组的出现次数。为了避免重复计算,只考虑 y ≤ z y \le z y≤z 的情况。该三元组的出现次数计算如下:
-
如果 y = z y = z y=z,则该三元组的出现次数是 xCount × yCount × ( yCount − 1 ) 2 \textit{xCount} \times \dfrac{\textit{yCount} \times (\textit{yCount} - 1)}{2} xCount×2yCount×(yCount−1);
-
如果 y < z y < z y<z,则该三元组的出现次数是 xCount × yCount × zCount \textit{xCount} \times \textit{yCount} \times \textit{zCount} xCount×yCount×zCount。
计算类型 2 2 2 的三元组的数目的方法大致相同,区别是在集合 set 2 \textit{set}_2 set2 中遍历元素 x x x,在集合 set 1 \textit{set}_1 set1 中遍历元素 y y y 并寻找元素 z z z。
得到类型 1 1 1 和类型 2 2 2 的三元组的数目之后,即可得到符合题目要求的三元组的数目。
代码
class Solution {
public int numTriplets(int[] nums1, int[] nums2) {
Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();
Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
for (int num : nums1) {
map1.put(num, map1.getOrDefault(num, 0) + 1);
}
for (int num : nums2) {
map2.put(num, map2.getOrDefault(num, 0) + 1);
}
return numTriplets(map1, map2) + numTriplets(map2, map1);
}
public int numTriplets(Map<Integer, Integer> map1, Map<Integer, Integer> map2) {
int triplets = 0;
Set<Integer> set1 = map1.keySet();
Set<Integer> set2 = map2.keySet();
for (int x : set1) {
long square = (long) x * x;
int xCount = map1.get(x);
for (int y : set2) {
if (square % y == 0 && square / y <= Integer.MAX_VALUE) {
int z = (int) (square / y);
if (!map2.containsKey(z)) {
continue;
}
int yCount = map2.get(y);
if (y == z) {
triplets += xCount * (yCount * (yCount - 1) / 2);
} else if (y < z) {
int zCount = map2.get(z);
triplets += xCount * yCount * zCount;
}
}
}
}
return triplets;
}
}
复杂度分析
-
时间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。遍历数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 并使用哈希表记录两个数组中的每个元素的出现次数需要 O ( m + n ) O(m + n) O(m+n) 的时间,计算类型 1 1 1 和类型 2 2 2 的三元组的数目各需要 O ( m n ) O(mn) O(mn) 的时间,因此总时间复杂度是 O ( m n ) O(mn) O(mn)。
-
空间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m 和 n n n 分别是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。需要使用两个哈希表分别记录数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 中的每个元素的出现次数,两个哈希表的空间分别是 O ( m ) O(m) O(m) 和 O ( n ) O(n) O(n)。