class Solution:
def numIdenticalPairs(self, nums):
from collections import defaultdict
count = defaultdict(int)
good_pairs = 0
for num in nums:
good_pairs += count[num]
count[num] += 1
return good_pairs
class Solution {
public:
int numIdenticalPairs(vector<int>& nums) {
unordered_map<int, int> count;
int good_pairs = 0;
for (int num : nums) {
good_pairs += count[num];
count[num]++;
}
return good_pairs;
}
};
class Solution {
public int numIdenticalPairs(int[] nums) {
Map<Integer, Integer> count = new HashMap<>();
int goodPairs = 0;
for (int num : nums) {
goodPairs += count.getOrDefault(num, 0);
count.put(num, count.getOrDefault(num, 0) + 1);
}
return goodPairs;
}
}
var numIdenticalPairs = function(nums) {
let count = {};
let goodPairs = 0;
for (let num of nums) {
goodPairs += (count[num] || 0);
count[num] = (count[num] || 0) + 1;
}
return goodPairs;
};
You are given an array of integers called nums
. Your task is to count the number of good pairs in the array. A good pair is defined as a pair of indices (i, j)
where i < j
and nums[i] == nums[j]
.
Key constraints:
i
must be less than j
.
At first glance, the problem seems to suggest checking every possible pair of indices in nums
and counting those where the elements are equal. This would involve two nested loops, comparing each pair (i
, j
) where i < j
. While this works for small arrays, it quickly becomes inefficient as the array grows.
Thinking further, we realize that for each number, the number of good pairs it contributes depends on how many times it has appeared so far. For each new occurrence, it forms a new good pair with each of its previous occurrences. This insight allows us to use a frequency counter (hash map) to keep track of how many times we've seen each value as we iterate.
This optimization shifts our approach from brute-force (comparing all pairs) to a single pass using a hash map, making the solution much faster and more efficient.
good_pairs
to 0. This will store our running total of good pairs.nums
from left to right.num
at index i
:
num
(from the hash map) to good_pairs
. This counts all good pairs that can be formed with previous occurrences of num
.num
in the hash map by 1.good_pairs
.This approach works efficiently because looking up and updating the hash map is a constant-time operation, and we only need to loop through the array once.
Let's use the sample input: nums = [1,2,3,1,1,3]
good_pairs = 0
.good_pairs
(still 0). Update hash map: {1: 1}.good_pairs
(still 0). Update: {1:1, 2:1}.good_pairs
(still 0). Update: {1:1, 2:1, 3:1}.good_pairs
(now 1). Update: {1:2, 2:1, 3:1}.good_pairs
(now 3). Update: {1:3, 2:1, 3:1}.good_pairs
(now 4). Update: {1:3, 2:1, 3:2}.The final answer is 4, which matches the number of good pairs: (0,3), (0,4), (3,4), and (2,5).
The optimized approach is much better for large arrays and is the preferred solution.
To solve the "Number of Good Pairs" problem, we count how many times each number has appeared as we traverse the array. For each new occurrence, we add the number of previous occurrences to our result. This simple use of a hash map allows us to avoid checking every pair and gives us an efficient, elegant solution.