Opening the reading…
Opening the reading…
HASHING › IMPLEMENTARY PROBLEMS
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →Start with one unordered pair of distinct values, such as {a, b}. Its product identifies the pair. Because all values in nums are distinct and positive, two different pairs with the same product cannot share an element: if a * b = a * c, then b = c. Therefore, every pair in one product group is automatically disjoint from every other pair in that group.
Suppose a product occurs for f unordered pairs. Choose any two of those pairs, giving f * (f - 1) / 2 choices. Each chosen pair can be ordered in two ways, and the two pair positions can be swapped, so each choice creates 2 * 2 * 2 = 8 tuples. The contribution is therefore f * (f - 1) / 2 * 8 = 4f(f - 1). Hashing lets you collect those frequencies without comparing every pair against every other pair.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n^2) | There are exactly n(n - 1) / 2 unordered pairs to process, and each pair performs constant-average-time hash-map work. The final map scan is no larger than the number of pairs, so it does not change the bound. |
| Space | O(n^2) extra | The map stores one frequency entry for each distinct product, with at most n(n - 1) / 2 entries when every pair has a different product. The returned count is a scalar output and is excluded from extra space; the worst shape is therefore quadratic map storage. |
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
int tupleSameProduct(vector<int>& nums) {
int n = nums.size();
unordered_map<int, int> freq;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
++freq[nums[i] * nums[j]];
}
}
int answer = 0;
for (const auto& entry : freq) {
int f = entry.second;
answer += 4 * f * (f - 1);
}
return answer;
}
};You can avoid the second scan by processing each unordered pair as soon as it is generated. If the current product has already appeared f times, the new pair forms f new selections with earlier pairs, and each selection contributes 8 tuples. Add 8 * f, then increment the frequency. This is merely a different arrangement, not an optimisation: it keeps the same O(n^2) time and O(n^2) worst-case extra space.
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
int tupleSameProduct(vector<int>& nums) {
int n = nums.size();
unordered_map<int, int> freq;
int answer = 0;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
int product = nums[i] * nums[j];
int previous = freq[product];
answer += 8 * previous;
++freq[product];
}
}
return answer;
}
};