Given an array of strings strs, group the anagrams together. You can return the answer in any order.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
Example 1:
Input: strs = ["eat","tea","tan","ate","nat","bat"] Output: [["bat"],["nat","tan"],["ate","eat","tea"]]
Example 2:
Input: strs = [""] Output: [[""]]
Example 3:
Input: strs = ["a"] Output: [["a"]]
Constraints:
1 <= strs.length <= 1040 <= strs[i].length <= 100strs[i]consists of lowercase English letters.
Approach 01:
-
C++
-
Python
#include <bits/stdc++.h>
#include <vector>
#include <string>
#include <map>
using namespace std;
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> groups;
for (const string& str : strs) {
string sorted_str = str;
sort(sorted_str.begin(), sorted_str.end());
groups[sorted_str].push_back(str);
}
vector<vector<string>> result;
for (const auto& pair : groups) {
result.push_back(pair.second);
}
return result;
}
};
from typing import *
from collections import *
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
groups = defaultdict(list)
for s in strs:
sorted_str = ''.join(sorted(s))
groups[sorted_str].append(s) # sorted_str working as key
return list(groups.values())
Time Complexity
- Sorting Each String: \( O(m \log m) \)
- Iterating Through All Strings:
- Sorting each string: \( O(m \log m) \) per string
- Inserting into unordered map: \( O(1) \) on average
- Overall Time Complexity: \( O(n \cdot m \log m) \)
Space Complexity
- unordered_map `groups`: \( O(n \cdot m) \)
- Vectors in `groups`: \( O(m) \) per string
- Overall Space Complexity: \( O(n \cdot m) \)
Approach 02:
-
C++
-
Python
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
int n = strs.size();
vector<vector<int>> result(n, vector<int>(26, 0));
vector<bool> visited(n, false);
vector<vector<string>> final_result;
// Calculate frequency arrays for each string
for (int i = 0; i < n; ++i) {
for (char ch : strs[i]) {
result[i][ch - 'a']++;
}
}
// Group anagrams
for (int i = 0; i < n; ++i) {
if (!visited[i]) {
vector<string> temp_list;
for (int j = i; j < n; ++j) {
if (result[i] == result[j] && !visited[j]) {
temp_list.push_back(strs[j]);
visited[j] = true;
}
}
final_result.push_back(temp_list);
}
}
return final_result;
}
};
from typing import *
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
n = len(strs)
result = []
final_result = []
for i in range(n):
num = [0]*26
for ch in strs[i]:
num[ord(ch) - ord('a')] += 1
result.append(num)
visited = []
for i in range(n):
temp = result[i]
temp_list = []
for j in range(i,n):
if(temp == result[j] and (j not in visited)):
temp_list.append(strs[j])
visited.append(j)
if(len(temp_list)!= 0):
final_result.append(temp_list)
return final_result
Time Complexity
Calculating Frequency Arrays:
\( O(n \cdot m) \), where \( n \) is the number of strings (\( \text{strs} \)) and \( m \) is the average length of strings.
Grouping Anagrams:
\( O(n^2 \cdot m) \), where \( n \) is the number of strings (\( \text{strs} \)) and \( m \) is the average length of strings.
Overall Time Complexity:
\( O(n^2 \cdot m) \), where \( n \) is the number of strings (\( \text{strs} \)) and \( m \) is the average length of strings.
Space Complexity
Frequency Arrays (\( \text{result} \)):
\( O(n \cdot m) \), where \( n \) is the number of strings (\( \text{strs} \)) and \( m \) is the size of the frequency array (constant 26 for each string).
Visited Array (\( \text{visited} \)):
\( O(n) \), where \( n \) is the number of strings (\( \text{strs} \)).
Final Result (\( \text{final_result} \)):
\( O(n \cdot m) \), in the worst case when no strings are grouped together.
Overall Space Complexity:
\( O(n \cdot m) \), where \( n \) is the number of strings (\( \text{strs} \)) and \( m \) is the average length of strings.