BackeasyHashing

String Cluster Formation Solution

Problem Statement

Given an array of strings, categorize them into groups where each group consists of strings that contain the same characters, regardless of their order.

Example 1
Input
['cat', 'tac', 'act', 'dog', 'god', 'good']
Output
['cat', 'tac', 'act', 'dog', 'god', 'good']

Explanation: Step-by-step: 1. Create a hashmap to store the sorted characters of each string as the key and the string itself as the value. 2. Iterate through the input array and for each string, sort its characters and use it as a key in the hashmap. If the key already exists, append the string to its value. If the key does not exist, add it to the hashmap with the string as its value. 3. Return the values of the hashmap as the result.

Example 2
Input
['abc', 'bca', 'cab', 'def', 'fed', 'ghi', 'hig', 'igh']
Output
['abc', 'bca', 'cab', 'def', 'fed', 'ghi', 'hig', 'igh']

Explanation: Step-by-step: 1. Create a hashmap to store the sorted characters of each string as the key and the string itself as the value. 2. Iterate through the input array and for each string, sort its characters and use it as a key in the hashmap. If the key already exists, append the string to its value. If the key does not exist, add it to the hashmap with the string as its value. 3. Return the values of the hashmap as the result.

Constraints

  • 1 <= number of strings <= 100
  • 1 <= length of each string <= 10
Live Compiler1 Free Run Available
Loading Editor...
Test Cases & Output
Click "Run" to test your 1 free compile trial!

🚀 Practice this problem

Run code, get AI hints & track streak

Sign Up Free

String Cluster Formation — Problem Statement & Solution Guide

HashingEasyGroup Anagrams
TimeO(n * m log m)
|
SpaceO(n * m)

Problem Description

Given an array of strings, categorize them into groups where each group consists of strings that contain the same characters, regardless of their order.

DSA Pattern Breakdown

DSA Pattern Breakdown

"String Cluster Formation"

easy

WHY DOES IT MATTER?

Grouping by character multiset is a classic example of using hashing to transform a complex comparison into a simple key lookup, dramatically reducing time complexity. It demonstrates how to turn a problem that naively requires pairwise checks into a linear-time solution by exploiting the commutative property of character counts.

OPTIMIZATION CHALLENGE

The bottleneck is the per-string transformation. By replacing an O(m^2) pairwise comparison with an O(m) or O(m log m) canonicalization and a hash map lookup, we reduce the overall complexity from quadratic to linear (up to a log factor).

REAL-WORLD CONNECTION

Think of a distributed log aggregation system where log entries are normalized before storage. Normalization (e.g., sorting fields or hashing) allows quick deduplication and efficient querying, just as canonical string signatures enable fast grouping.

When explaining this in an interview, emphasize the equivalence relation and the role of the hash map. Show that the key is deterministic and that the algorithm is essentially a single-pass map construction, which is a pattern candidates should recognize.

COMPLEXITY AT A GLANCE

⏱ Time:O(n * m log m)
💾 Space:O(n * m)

Core Theory — Why This Approach?

The problem reduces to identifying an equivalence relation on strings: two strings are equivalent if they contain exactly the same multiset of characters, regardless of order. A naive approach would compare each pair of strings, leading to O(n^2 * m) time where n is the number of strings and m is the average length, which quickly becomes infeasible for large inputs. The optimal paradigm is to transform each string into a canonical representation that captures its character multiset—either by sorting its characters (O(m log m)) or by counting character frequencies (O(m) for fixed alphabet). This canonical form can then be used as a key in a hash map to group strings in a single pass, yielding O(n * m log m) time with O(n * m) auxiliary space, or O(n * m) time if a fixed-size frequency array is used.

Sorting each string is straightforward and works for arbitrary alphabets, but it incurs a logarithmic factor per string. For typical English letters or ASCII, a counting sort approach using a 26 or 128-length array produces a fixed-size signature (e.g., "a1b2c0..."), which is both faster and more space-efficient. In either case, the hash map ensures that strings with identical signatures are placed in the same bucket, achieving the desired grouping in linear time relative to the total input size.

The key insight is that the grouping operation is essentially a hashing problem: we need a hashable key that uniquely identifies the character multiset. By precomputing this key once per string and using a dictionary, we avoid repeated pairwise comparisons and reduce the complexity from quadratic to linear (up to a logarithmic factor for sorting).

Interview Questions on This Problem

Q1How would you modify the algorithm if the strings could contain Unicode characters beyond the ASCII range?

For Unicode, you can still use a frequency map but the key must accommodate a larger alphabet. One approach is to sort the string using a Unicode-aware sort, which is O(m log m), or to use a hash of the sorted string. Alternatively, you can use a dictionary to count occurrences of each code point, then serialize the dictionary (e.g., as a tuple of sorted (char, count) pairs) to serve as the hash key. This keeps the algorithm O(n * m log m) but handles arbitrary Unicode.

Q2In a distributed system where the list of strings is partitioned across multiple nodes, how would you aggregate the groups efficiently?

Each node can independently compute the canonical key for its local strings and emit key-value pairs (key, string). A shuffle phase (e.g., MapReduce) then groups all values by key across nodes. Since the key is deterministic, identical groups will be co-located, and the final aggregation is a simple concatenation of lists per key. This approach scales linearly with the number of nodes and avoids cross-node comparisons.

Q3What trade-offs arise if you choose to use a sorted string as the key versus a frequency array string?

Using a sorted string is simpler to implement and works for any alphabet, but it incurs O(m log m) time per string and the key length is m, which can be large. A frequency array key is O(m) time and produces a fixed-size key (e.g., 26 integers for lowercase letters), which is faster and uses less memory for large strings. However, it requires knowledge of the alphabet size and may be less flexible for arbitrary character sets.

Examples

Example 1

Input

['cat', 'tac', 'act', 'dog', 'god', 'good']

Output

['cat', 'tac', 'act', 'dog', 'god', 'good']

Explanation: Step-by-step: 1. Create a hashmap to store the sorted characters of each string as the key and the string itself as the value. 2. Iterate through the input array and for each string, sort its characters and use it as a key in the hashmap. If the key already exists, append the string to its value. If the key does not exist, add it to the hashmap with the string as its value. 3. Return the values of the hashmap as the result.

Example 2

Input

['abc', 'bca', 'cab', 'def', 'fed', 'ghi', 'hig', 'igh']

Output

['abc', 'bca', 'cab', 'def', 'fed', 'ghi', 'hig', 'igh']

Explanation: Step-by-step: 1. Create a hashmap to store the sorted characters of each string as the key and the string itself as the value. 2. Iterate through the input array and for each string, sort its characters and use it as a key in the hashmap. If the key already exists, append the string to its value. If the key does not exist, add it to the hashmap with the string as its value. 3. Return the values of the hashmap as the result.

Constraints

  • 1 <= number of strings <= 100
  • 1 <= length of each string <= 10

Optimal Approach & Strategy

For each string, compute a canonical key (sorted characters or frequency counts) in O(m log m) or O(m) time, then insert the string into a hash map keyed by that signature. Finally, collect the values of the map as the groups. This runs in O(n * m log m) time and uses O(n * m) space.

Brute Force Approach

Compare every pair of strings to see if they contain the same characters, adding them to the same group if they do. This requires O(n^2 * m) time and is impractical for large inputs.

Verified Code Solutions

JavaScript Solution
Time: O(n * m log m)
function groupStrings(strs) {
   const hashmap = {};
   for (const str of strs) {
       const sortedStr = str.split('').sort().join('');
       if (hashmap[sortedStr]) {
           hashmap[sortedStr].push(str);
       } else {
           hashmap[sortedStr] = [str];
       }
   }
   return Object.values(hashmap);
}

Solve in Interative Editor

Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.