Grouping Names Solution C++
Creato il: 4 febbraio 2025
Risposto usando O3 Mini High da Chat01
Creato il: 4 febbraio 2025
Risposto usando O3 Mini High da Chat01
Here is the problem statement extracted from the images:
You are given an array of N names. Each name consists of uppercase English letters. You need to form groups of names based on the set of unique alphabets they contain.
A name A can be in the same group as name B if the set of unique characters in A and B differs by at most one character in one of the following ways:
Your task is to determine:
For each test case, print two space-separated integers:
text1 5 HARI HARRY LATA SARAI
3 2
Would you like a solution in a specific programming language? code in c++
We can solve the problem by “compressing” each name into a 26‐bit mask (one bit per uppercase letter) that indicates which letters occur in the name. Then two names are “similar” (and hence can be in the same group) if their bitmasks differ by at most one allowed operation. In our case the allowed operations are:
Addition: One name’s letter set is exactly the other’s plus one extra letter. (For example, if and .)
‒ In terms of bitmasks: if for some letter not in .
Removal: The reverse of addition (one letter is “missing”).
‒ That is, is with one extra letter.
Replacement: The two names have the same number of letters but exactly one letter is “swapped”.
‒ In bitmask terms, if and have the same popcount and if one letter is removed and a different one is added (so the symmetric difference has size 2).
Notice that if the two masks are identical (i.e. symmetric difference is 0) they are automatically “similar” and all names with the same mask will belong together.
The idea is to build a graph where each vertex is a unique bitmask (with a frequency count equal to how many names produced that mask). We add an edge between two vertices if one of the allowed operations transforms one mask into the other. Then, grouping the names is the same as finding the connected components in this graph.
A few implementation details:
Below is the complete C++ solution:
cpp#include <bits/stdc++.h> using namespace std; // Disjoint Set Union (Union–Find) structure struct DSU { vector<int> parent, rank; DSU(int n) : parent(n), rank(n,0) { for (int i = 0; i < n; i++) parent[i] = i; } int find(int a) { return parent[a] = (parent[a] == a ? a : find(parent[a])); } void unite(int a, int b) { a = find(a); b = find(b); if(a == b) return; if(rank[a] < rank[b]) swap(a, b); parent[b] = a; if(rank[a] == rank[b]) rank[a]++; } }; // Convert a name (string) into a bitmask representing its unique letters. int nameToMask(const string &s) { int mask = 0; for (char c : s) mask |= 1 << (c - 'A'); return mask; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while(T--){ int N; cin >> N; // Compress names by their unique letter bitmask. unordered_map<int, int> freq; // mask -> frequency count vector<int> uniqueMasks; // list of unique masks for (int i = 0; i < N; i++){ string name; cin >> name; int mask = nameToMask(name); if(freq.find(mask) == freq.end()){ freq[mask] = 0; uniqueMasks.push_back(mask); } freq[mask]++; } int sz = uniqueMasks.size(); // Map each unique mask to an index (for DSU). unordered_map<int,int> maskToIndex; for (int i = 0; i < sz; i++){ maskToIndex[ uniqueMasks[i] ] = i; } DSU dsu(sz); // For each unique mask, generate all neighbors by allowed operations. for (int i = 0; i < sz; i++){ int m = uniqueMasks[i]; // Operation 1: Add a letter (if not already present). for (int bit = 0; bit < 26; bit++){ if (!(m & (1 << bit))){ int candidate = m | (1 << bit); if(maskToIndex.find(candidate) != maskToIndex.end()){ dsu.unite(i, maskToIndex[candidate]); } } } // Operation 2: Remove a letter (if present). for (int bit = 0; bit < 26; bit++){ if (m & (1 << bit)){ int candidate = m & ~(1 << bit); if(maskToIndex.find(candidate) != maskToIndex.end()){ dsu.unite(i, maskToIndex[candidate]); } } } // Operation 3: Replace a letter. // For each letter present, remove it then add a different letter. for (int bit = 0; bit < 26; bit++){ if(m & (1 << bit)){ int removed = m & ~(1 << bit); for (int bit2 = 0; bit2 < 26; bit2++){ // We must add a letter that is not already in the removed mask. // (Note: When bit2 == bit, candidate would become the original m.) if(removed & (1 << bit2)) continue; int candidate = removed | (1 << bit2); if(maskToIndex.find(candidate) != maskToIndex.end()){ dsu.unite(i, maskToIndex[candidate]); } } } } } // Now compute the connected components. // For each component, add up the frequencies (i.e. number of names with those masks). vector<long long> compFreq(sz, 0); unordered_set<int> compRoots; for (int i = 0; i < sz; i++){ int root = dsu.find(i); compFreq[root] += freq[ uniqueMasks[i] ]; compRoots.insert(root); } int numGroups = compRoots.size(); long long maxGroupSize = 0; for (int root : compRoots) maxGroupSize = max(maxGroupSize, compFreq[root]); cout << maxGroupSize << " " << numGroups << "\n"; } return 0; }
Input and Mask Conversion:
We read each name and compute its bitmask using the nameToMask
function. Names with the same mask are “compressed” (we record their frequency).
Graph Construction (via DSU):
For every unique mask we generate candidate masks using:
For every candidate that exists in our dictionary (i.e. was produced by some name), we unite the two nodes in our DSU.
Computing the Answer:
After union–find, each DSU “root” represents one group. We sum the frequencies (number of names) in each group. Finally, we output:
This solution meets the problem’s constraints efficiently.
Would you like further clarification on any part of the code?