Effective Strategies to Conquer Anagrams, Group Anagrams, and Two Sum Challenges on LeetCode


Anagram:
An Anagram is a string that contains the same characters as another string, but the order can be different.
Example:
class Solution:
def isAnagram(self, s:str, t:str) -> bool:
return sorted(s) == sorted(t)
# Example usage:
s = "anagram"
t = "nagaram"
print(isAnagram(s, t)) # Output: True
s = "rat"
t = "car"
print(isAnagram(s, t)) # Output: False
The Code Explanation:
→ This Code checks and returns whether a string is an Anagram or not.
1. The code explains a function checking the string for anagrams.
2. When s is ‘anagram‘ and t is ‘nagaram‘, then we print the function with parameters. If the string value in s matches the string value in t, then it prints true.
3. If the values of both strings didn't match, it prints False.
Time complexity: O(nlogn+mlogm)O(nlogn+mlogm)
Space complexity: O(1) or O(n+m) depending on the sorting algorithm.
Grouping Anagrams:
Here, the array of strings that are anagrams is grouped with the corresponding strings in any order.
The Core Idea:
Anagrams are words made of the same letters, just in a different order. This means they will have the exact same count of each letter*. We can use this letter count as a unique “signature“ or “key“ to group them.
Example:*
Given an array of strings strs, group the anagrams together. You can return the answer in any order.
*Input: *[“eat“, “tea“, “Tan“, “ate“, “nat“, “bat“]
*Expected Output: [[“bat“], [“nat“, “tan“], [“ate“, “eat“, “tea“]]
class Solution:
def groupAnagrams(self,strs):
res = defaultdict(list)
for s in strs:
count = [0] * 26 # a ... z
for c in s:
count[ord(c) - ord('a')] += 1
res[tuple(count)].append(s)
return list(res.values())
# Example usage:
strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
solution = Solution()
print(solution.groupAnagrams(strs))
Code Explanation:
Step 1: The Alphabet Blueprint - A list of 26 Zeros*We start by creating a template to count the letters from a to z. A list with 26 zeros is perfect for this. Each position (or index) in the list corresponds to a letter of the alphabet.
→ Index 0 represents the count of ‘a‘.
→ Index 1 represents the count of ‘b‘.
→ …and so on, up to index 25 for ‘z‘.
Step 2: Processing a Word and Updating Counts*Now, we’ll process a word, for example, “eat“. We go through it letter by letter and increase the count at the corresponding index in our list.
How do we find the index for a letter?
We use a simple formula: index = ord(character) - ord(‘a‘). The ord function gives us the ASCII value of a character.
→ For ‘e‘: ord(‘e‘) - ord(‘a‘) = 101 - 97 = 4. So, we increment the count at index 4.
→ for ‘a‘: ord(‘a‘) - ord(‘a‘) = 97 - 97 = 0. We increment the count at index 0.
→ for ‘t‘: ord(‘t‘) - ord(‘a‘) = 116- 97 = 19. We increment the count at index 19.
Step 3: Creating an Immutable Signature - Converting the list to a tuple, our count list [1, 0, 0, 0, 1, …, 1, …] is the signature for “eat”.
However, in Python, we want to use these signatures as keys in a dictionary to group the words. Lists are mutable (changeable) and cannot be used as dictionary keys.
So, we convert the list into a tuple. Tuples are immutable (unchangeable)
and cannot be used as dictionary keys.
Step 4: Grouping the words in a Dictionary
We use a dictionary (or a defaultdict) to store our groups. The tuple signature is the key, and the value is a list of words that match that signature.
Let us see how it works for a few words:
1. ***Word: “eat“*→ Generates Signature: (1, 0, …, 1, …, 1, …)
→ The dictionary is updated: { (signature) : [“eat“]}
2. Word “tea*“
→ It contains one ‘t‘, one ‘e‘, one ‘a‘.
→ It generates the \**EXACT SAME signature: (1, 0, …, 1, …, 1, …)*→ The Dictionary finds this key and appends “tea“: { (signature): [“eat“, “tea“]}
3. Word: “bat“*
→ It contains one ‘b‘, one ‘a’, one ‘t‘.
→ It generated DIFFERENT signature (with counts ‘a‘, ‘b‘, ‘t‘).
→ A new entry is created in the dictionary: {…, (new_signature) : [“bat“]}*
Time complexity: O(m∗n)O(m∗n)
Space complexity:
O(m)O(m) extra space.
O(m∗n)O(m∗n) space for the output list
Two Sum
Two Sum is a basic problem asked in most of the MNCs in technical interviews.
What is the Two-Sum Problem?
The Two-Sum Problem asks you to find two numbers in a given array that their sum equals a specified target number. You must return their indices, not the numbers themselves.
Why is it important?
It helps beginners understand:
1. Hashmaps (Dictionaries)
2. Time Complexity optimization (from O(n²) to O(n))
3. Fundamental problem-solving strategies used in coding interviews(Google, Amazon, etc.)
When is Two Sum used?
It’s often used as a coding interview question to test your understanding of:
→ Arrays
→ Hashmaps
→ Algorithmic thinking
It also serves as a foundation for harder problems like 3Sum, 4Sum, and Subarray Sum problems.
Where is it applied in real life?
Conceptually similar ideas are applied in :
→ Financial apps: Finding a pair of expenses within budget.
→ Gaming: Pairing scores or items to reach a target.
→ Data Analysis: Finding two metrics that sum to a desired outcome.
Example code:
Given: An Array of Integers nums
and an integer target
.
Task: Find two numbers in the array such that they add up to the target, and return their indices.
You may assume:
1. There is exactly one Solution.
2. You cannot use the same element twice
class Solution:
def twoSum(self, nums, target):
prevMap = {} # value : index
for i,n in enumerate(nums):
diff = target - n
if diff in prevMap:
return [prevMap[diff], i]
prevMap[n] = i
return
# Example Usage:
nums = [2, 7, 11, 15]
target = 9
result = twoSum(nums, target)
print(result) # Output: [0, 1] (Because nums[0] + nums[1] = 2 + 7 = 9)
1. PrevMap is a Dictionary that Stores the number Value and its index. We have seen while Looping
Example,
If nums = [2, 7, 11 ,15]
prevMap would be like (2 : 0)
2. ***For i,n enumerate(nums)*Loops through the list nums
1. i is the index
2. n is the number at the index
3. diff = target - n*
For the current number n,
What number do we need to reach the target?
1. Diff is the missing number we are looking for
Example,
→ If the target is 9 and n = 2,
then diff = 7 (because(2 + 7 = 9))*
4. It means we already saw a number earlier that fits this pair.
Return its index and current index.
i.e.,
nums = [2, 7]
target = 9
prevMap = {2 : 0}
diff (2) is in prevMap → return[0, 1]
prevMap[n] = 1
If diff not found, store n with its index i for future, and then return
Time Complexity : O(n)
Space Complexity : O(n)
Subscribe to my newsletter
Read articles from Sam Anirudh Malarvannan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
