- Notifications
You must be signed in to change notification settings - Fork 2
feat(strings, anagrams): group anagrams #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits Select commit Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # Group Anagrams | ||
| | ||
| Given a list of words or phrases, group the words that are anagrams of each other. An anagram is a word or phrase formed | ||
| from another word by rearranging its letters. | ||
| | ||
| Constraints: | ||
| | ||
| Let `strs` be the list of strings given as input to find the anagrams. | ||
| | ||
| - 1 <= `strs.length` <=10^3 | ||
| - 0 <= `strs[i].length` <= 100 | ||
| - `strs[i]` consists of lowercase English letters | ||
| | ||
| > Note the order in which the output is displayed doesn't matter | ||
| | ||
| ## Examples | ||
| | ||
|  | ||
|  | ||
| | ||
| | ||
| |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| from typing import List, Dict, Tuple | ||
| from collections import defaultdict | ||
| | ||
| | ||
| def group_anagrams_naive(strs: List[str]) -> List[List[str]]: | ||
| """ | ||
| Groups a list of strings by their anagrams. | ||
| Parameters: | ||
| strs (List[str]): A list of strings | ||
| Returns: | ||
| List[List[str]]: A list of lists, where each inner list contains strings that are anagrams of each other | ||
| """ | ||
| word_map: Dict[str, List[str]] = defaultdict(list) | ||
| # traversing the list of strings takes O(n) time where n is the number of strings in this list | ||
| for word in strs: | ||
| # Note that the sorting here takes O(nlog(n)) time were n is the number of characters in this string | ||
| key = "".join(sorted(word.lower())) | ||
| word_map[key].append(word) | ||
| | ||
| return list(word_map.values()) | ||
| | ||
| def group_anagrams(strs: List[str]) -> List[List[str]]: | ||
| """ | ||
| Groups a list of strings by their anagrams. | ||
| This uses A better approach than sorting can be used to solve this problem. This solution involves computing the | ||
| frequency of each letter in every string. This will help reduce the time complexity of the given problem. We’ll just | ||
| compute the frequency of every string and store the strings in their respective list in a hash map. | ||
| We see that all members of each set are characterized by the same frequency of each letter. This means that the | ||
| frequency of each letter in the words belonging to the same group is equal. In the set [["speed", "spede"]], the | ||
| frequency of the characters s, p, e, and d are the same in each word. | ||
| Let’s see how we can implement the above algorithm: | ||
| - For each string, compute a 6-element list. Each element in this list represents the frequency of an English letter | ||
coderabbitai[bot] marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| in the corresponding string. This frequency count will be represented as a tuple. For example, "abbccc" will be | ||
| represented as (1, 2, 3, 0, 0, ..., 0). This mapping will generate identical lists for strings that are anagrams. | ||
| - Use this list as a key to insert the strings into a hash map. All anagrams will be mapped to the same key in this | ||
| hash map. | ||
| - While traversing each string, we generate its 26-element list and check if this list is present as a key in the | ||
| hash map. If it does, we'll append the string to the array corresponding to that key. Otherwise, we'll add the new | ||
| key-value pair to the hash map. | ||
| - Return the values of the hash map in a two-dimensional array, since each value will be an individual set of | ||
| anagrams. | ||
| Parameters: | ||
| strs (List[str]): A list of strings | ||
| Returns: | ||
| List[List[str]]: A list of lists, where each inner list contains strings that are anagrams of each other | ||
| """ | ||
| word_map: Dict[Tuple[int,...], List[str]] = defaultdict(list) | ||
| # traversing the list of strings takes O(n) time where n is the number of strings in this list | ||
| for word in strs: | ||
| count = [0] * 26 | ||
| for char in word: | ||
| index = ord(char) - ord('a') | ||
| count[index] += 1 | ||
BrianLusina marked this conversation as resolved. Outdated Show resolved Hide resolved | ||
| | ||
| key = tuple(count) | ||
| word_map[key].append(word) | ||
| | ||
| return list(word_map.values()) | ||
Binary file added BIN +25.2 KB pystrings/anagram/group_anagrams/images/group_anagrams_example_one.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added BIN +21.5 KB pystrings/anagram/group_anagrams/images/group_anagrams_example_two.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import unittest | ||
| from . import group_anagrams | ||
| | ||
| | ||
| class GroupAnagramsTestCase(unittest.TestCase): | ||
| def test_1(self): | ||
| strs = ["eat", "beat", "neat", "tea"] | ||
| expected = [["eat", "tea"], ["beat"], ["neat"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
BrianLusina marked this conversation as resolved. Show resolved Hide resolved | ||
| | ||
| def test_2(self): | ||
| strs = ["duel", "dule", "speed", "spede", "deul", "cars"] | ||
| expected = [["duel", "dule", "deul"], ["speed", "spede"], ["cars"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| def test_3(self): | ||
| strs = ["eat","tea","tan","ate","nat","bat"] | ||
| expected = [["eat","tea","ate"],["tan","nat"],["bat"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| def test_4(self): | ||
| strs = ["word","sword","drow","rowd","iced","dice"] | ||
| expected = [["word","drow","rowd"],["sword"],["iced","dice"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| def test_5(self): | ||
| strs = ["eat","drink","sleep","repeat"] | ||
| expected = [["eat"],["drink"],["sleep"],["repeat"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| def test_6(self): | ||
| strs = ["hello","ohlle","dark"] | ||
| expected = [["hello","ohlle"],["dark"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| def test_7(self): | ||
| strs = ["eat","beat","neat","tea"] | ||
| expected = [["eat","tea"],["beat"],["neat"]] | ||
| actual = group_anagrams(strs) | ||
| self.assertEqual(expected, actual) | ||
| | ||
| | ||
| if __name__ == '__main__': | ||
| unittest.main() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.