题目描述:
给你一个整数数组 nums
。
如果一组数字 (i,j)
满足 nums[i]
== nums[j]
且 i
< j
,就可以认为这是一组 好数对 。
返回好数对的数目。
示例 1:
输入:nums = [1,2,3,1,1,3] 输出:4 解释:有 4 组好数对,分别是 (0,3), (0,4), (3,4), (2,5) ,下标从 0 开始示例 2:
输入:nums = [1,1,1,1] 输出:6 解释:数组中的每组数字都是好数对示例 3:
输入:nums = [1,2,3] 输出:0提示:
1 <= nums.length <= 100
1 <= nums[i] <= 100
代码实现:
方法一:可以通过暴力枚举的方式来求解。可以使用两个嵌套的循环,外层循环枚举所有可能的位置 i,内层循环枚举 i 后面的位置 j,如果 nums[i] == nums[j],则说明找到了一组好数对,累加计数器即可。
public int numIdenticalPairs(int[] nums) {
int n = nums.length;
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (nums[i] == nums[j]) {
count++;
}
}
}
return count;
}
该方法的时间复杂度为 O(n^2),空间复杂度为 O(1)。
方法二:可以利用哈希表来记录每个数字出现的次数。
具体步骤如下:
map
,用于记录数组中每个数字出现的次数。nums
,对于每个数字 num
,将其在哈希表中对应的计数器加一。map
,对于每个数字出现的次数 count
,好数对的数量为 count * (count - 1) / 2
,将其累加到结果 ans
中。ans
。public int numIdenticalPairs(int[] nums) {
Map map = new HashMap<>();
int count = 0;
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
for (int num : map.keySet()) {
int freq = map.get(num);
count += freq * (freq - 1) / 2;
}
return count;
}
这种方法的时间复杂度为 O(n),其中 n 是数组 nums
的长度。需要遍历两次数组,第一次遍历统计每个数字出现的次数,第二次遍历计算好数对的数量。空间复杂度为 O(n),用于存储哈希表。相较于暴力枚举的方法,这种方法的效率更高。
(第二种方法不是很能理解O.o...),
count += freq * (freq - 1) / 2;
这句代码的作用是计算出当前数字 num
的好数对数量,并将其累加到变量 count
上。
具体来说,如果一个数字在数组中出现了 freq
次,那么它可以组成的好数对数量为 freq * (freq - 1) / 2
。这个公式的解释如下:
假设这个数字出现在数组中的位置分别为 i1, i2, ..., ifreq
,那么它可以和其他数字组成的好数对数量就是
C(freq, 2) = freq! / (2! * (freq - 2)!) = freq * (freq - 1) / 2
其中 C(n, m)
表示从 n 个元素中选取 m 个元素的组合数。
因为一个数字出现 freq
次,所以它可以和其他任意一个相同的数字组成一组好数对,因此它能够组成的好数对数量就是 C(freq, 2)
。
最后,我们遍历哈希表中的每个数字,将它们的好数对数量相加得到总的好数对数量,即为变量 count
的值。
总之,这句代码的作用是将当前数字能够组成的好数对数量累加到计数器上。