Two strings X and Y are considered similar if either they are identical or we can make them equivalent by swapping at most two letters (in distinct positions) within the string X.
For example, "tars" and "rats" are similar (swapping at positions 0 and 2), and "rats" and "arts" are similar, but "star" is not similar to "tars", "rats", or "arts".
Together, these form two connected groups by similarity: {"tars", "rats", "arts"} and {"star"}. Notice that "tars" and "arts" are in the same group even though they are not similar.
Formally, each group is such that a word is in the group if and only if it is similar to at least one other word in the group.
We are given a list strs of strings where every string in strs is an anagram of every other string in strs. How many groups are there?
Input & Output
Example 1 — Basic Grouping
$Input:strs = ["tars","rats","arts","star"]
›Output:2
💡 Note:"tars" and "rats" are similar (swap positions 0,2). "rats" and "arts" are similar (swap positions 0,1). So {"tars","rats","arts"} form one group. "star" forms its own group. Total: 2 groups.
Example 2 — All Connected
$Input:strs = ["abc","bac"]
›Output:1
💡 Note:"abc" and "bac" are similar by swapping positions 0 and 1. Both strings form one group.
Example 3 — All Separate
$Input:strs = ["abc","def","ghi"]
›Output:3
💡 Note:None of the strings are similar to each other (would need more than 2 swaps). Each string forms its own group.
Constraints
1 ≤ strs.length ≤ 300
1 ≤ strs[i].length ≤ 300
strs[i] consists of lowercase letters only
All the strings of strs are the same length
All the strings of strs are anagrams of each other
The key insight is to model this as a graph connectivity problem. Two strings are similar if they differ by at most 2 character positions. We need to find connected components where strings are transitively connected through similarity relationships. The Union-Find approach is most efficient with time complexity O(n² × m × α(n)) and space O(n).
Common Approaches
✓
Brute Force with DFS
⏱️ Time: O(n² × m)
Space: O(n²)
Build an adjacency list by checking every pair of strings for similarity, then use DFS to count connected components. Two strings are similar if they are identical or differ by exactly 2 positions.
Union-Find (Disjoint Set)
⏱️ Time: O(n² × m × α(n))
Space: O(n)
Build Union-Find structure and union strings that are similar. Each connected component represents a group. More efficient than DFS for this type of connectivity problem.
Brute Force with DFS — Algorithm Steps
Check all pairs of strings for similarity
Build adjacency graph
Use DFS to find connected components
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Build Graph
Check all pairs for similarity and create connections
2
DFS Traversal
Visit connected components to identify groups
3
Count Groups
Each DFS traversal represents one group
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool isSimilar(const char* s1, const char* s2) {
if (strcmp(s1, s2) == 0) return true;
int diffCount = 0;
int len = strlen(s1);
for (int i = 0; i < len; i++) {
if (s1[i] != s2[i]) {
diffCount++;
if (diffCount > 2) return false;
}
}
return diffCount == 2;
}
void dfs(int** graph, int* graphSizes, bool* visited, int node) {
visited[node] = true;
for (int i = 0; i < graphSizes[node]; i++) {
int neighbor = graph[node][i];
if (!visited[neighbor]) {
dfs(graph, graphSizes, visited, neighbor);
}
}
}
int solution(char** strs, int n) {
if (n <= 1) return n;
// Build adjacency list
int** graph = (int**)malloc(n * sizeof(int*));
int* graphSizes = (int*)calloc(n, sizeof(int));
int* graphCapacity = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
graph[i] = (int*)malloc(n * sizeof(int));
graphCapacity[i] = n;
}
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (isSimilar(strs[i], strs[j])) {
graph[i][graphSizes[i]++] = j;
graph[j][graphSizes[j]++] = i;
}
}
}
// DFS to count connected components
bool* visited = (bool*)calloc(n, sizeof(bool));
int groups = 0;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
dfs(graph, graphSizes, visited, i);
groups++;
}
}
// Cleanup
for (int i = 0; i < n; i++) {
free(graph[i]);
}
free(graph);
free(graphSizes);
free(graphCapacity);
free(visited);
return groups;
}
void parseArray(const char* str, int* arr, int* size) {
*size = 0;
const char* p = str;
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',') p++;
if (*p == ']' || *p == '\0') break;
arr[(*size)++] = (int)strtol(p, (char**)&p, 10);
}
}
int main() {
char line[10000];
fgets(line, sizeof(line), stdin);
// Parse JSON array manually
char** strs = (char**)malloc(100 * sizeof(char*));
int n = 0;
char* ptr = strchr(line, '[');
if (ptr) {
ptr++;
char* token = strtok(ptr, ",]");
while (token && n < 100) {
// Remove quotes and whitespace
while (*token == ' ' || *token == '"') token++;
char* end = token + strlen(token) - 1;
while (end > token && (*end == ' ' || *end == '"' || *end == '\n')) {
*end = '\0';
end--;
}
strs[n] = (char*)malloc((strlen(token) + 1) * sizeof(char));
strcpy(strs[n], token);
n++;
token = strtok(NULL, ",]");
}
}
printf("%d\n", solution(strs, n));
// Cleanup
for (int i = 0; i < n; i++) {
free(strs[i]);
}
free(strs);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(n² × m)
n² pairs to check, each similarity check takes O(m) where m is string length
n
2n
⚠ Quadratic Growth
Space Complexity
O(n²)
Adjacency list can store up to n² edges in worst case
n
2n
⚠ Quadratic Space
28.5K Views
MediumFrequency
~35 minAvg. Time
892 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.