3

I am trying to define a function that takes 2 strings, compare those two and returns True if they are anagram. I don't want to import collections.

So, if string1 is python and string 2 is nohtyp, it should return True. Otherwise, obviously, return false. Here's my code looks like so far:

def check_anagram(str1, str2):
if len(str1) != len(str2):
    return False
else:
    for i in range(0, len(str1), 1):
        if i in range(0, len(str2), 1):
            return True
        else:
            return False

It works well for most of cases, but when str1 is aaaaaaaaaabbbbbbbbbb and str2 is ababababbbababababab, it returns true and when str1 is xxxyyyxxx and str2 is yyyxxxyyy, it also returns True.

It should retrun False for these 2 cases, but I have no idea. Can anybody help me with this?

Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
Auclown
  • 179
  • 1
  • 3
  • 20

4 Answers4

1

Your two test cases are returning true because you don't remove characters from str2 after you've checked they exist. So for example comparing the following two strings:

str1 = aa and str2 = a

we would expect the result of your comparison to be False, because they obviously are not anagrams. But, checking each of the two a characters in str1 will return True, because str2 also contains a. A better (and faster) way might be to process the strings first, like so:

# return a dictionary, where each key is the 
# count of that letter in the string
def process_str(str):
    dic = {}
    for letter in str:
        if letter in dic:
            dic[letter] += 1
        else:
            dic[letter] = 1
    return dic

def check_anagram(str1, str2):
    dic1 = process_str(str1)
    dic2 = process_str(str2)

    # does every key in dic1 have a corresponding key in dic2?
    for key in dic1:
        if not key in dic2:
            return False
        if not dic1[key] == dic2[key]:
            return False

    # does every key in dic2 have a corresponding key in dic1?
    for key in dic2:
        if not key in dic1:
            return False
        if not dic1[key] == dic2[key]:
            return False

    return True

That should do the trick.

Rob Gwynn-Jones
  • 677
  • 1
  • 4
  • 14
1

I think the most trivial way to do the task is sorting your strings and comparing them like this example:

def check_anagram(a = '', b = ''):
    return sorted(a) == sorted(b)

Test1:

a = "python"
b = "nohtyp"
print(check_anagram(a, b))

Output:

>>> True

Test2:

a = "aaaaaaaaaabbbbbbbbb"
b = "ababababbbababababab"
print(check_anagram(a, b))

Output:

>>> False

Test3:

a = "xxxyyyxxx"
b = "yyyxxxyyy"
print(check_anagram(a, b))

Output:

>>> False
Chiheb Nexus
  • 9,104
  • 4
  • 30
  • 43
  • 1
    easiest way to solve my problem! thank you. but i dont know if i will be able to use 'sort' method to deal with my assignment. but still, thanks. – Auclown Mar 20 '17 at 23:27
  • 1
    You didn't say that in your question. But still you have an idea of how to deal it using sorted strings. – Chiheb Nexus Mar 20 '17 at 23:34
  • If the user inputs an uppercase letter in the word, this would fail. We should also consider using sorted().lower() or sorted().upper() to cover this. – ParvBanks Dec 05 '18 at 13:02
  • Do, put a and to lower then ckech if they're anagram – Chiheb Nexus Dec 05 '18 at 14:57
1

Currently, your code will always return True.

for i in range(0, len(str1), 1):

this will iterate over the range of the length of str1, if the string is "python" The for loop will have these values for 'i': 0, 1, 2, 3, 4, 5 If you want to iterate over every single letter write

for i in str1:

This will make the values of i: p, y, t, h, o, n

Alternatively, if you use a range, you can check the individual letters with str1[i]. This will output the following: str1[0] == "p", str1[1] == "y" etc.

Since you do the same in your if statement, it will check if 'i' from range(0, 6) is equal to i. The first value of 'i' will be 0, after this first check it pass the if statement and will return True, meaning it will end the loop. This means it will only check this first case.

What you want to do is check over every letter in str1, if it is anywhere in str2, remove that instance from str2 and check the next letter. If at any time the letter is NOT in str2, return False. After checking all the letters and you didn't return False, return True.

Since strings are immutable, you can put them in a list first, and iterate over the list.

Check out the following code:

def check_anagram(str1, str2):
    if len(str1) != len(str2):
        return False
    else:
        string1 = [x for x in str1] # put str1 in list string1
        string2 = [x for x in str2]
        for i in range(0, len(str2), 1): # iterate over the range (length) of str2
            if string1[i] in string2: # if letter in position i of string1 occurs in string 2 then:
                string2.remove(string1[i]) # remove that letter from the string2 list
            else: 
                return False # if it does NOT occur in string2, it is NOT an anagram, so return false
        return True # If the loop went correctly, return true

edit: If you want to remove whitespace (spaces) (since "ars magna" is an anagram of "anagrams", but the program won't pick it up since the length differs) you have to do this at the start. Replacing whitespace in a string can be done by the .replace(WHAT TO REPLACE, REPLACE WITH THIS) function. Place this right at the beginning of the check_anagram function:

str1 = str1.replace(" ", "")
str2 = str2.replace(" ", "")
1

There is a very quick way for checking if two strings are anagram.

This is the answer for the leetcode question https://leetcode.com/problems/valid-anagram/ as well.

Algorithm

1. Check if the length of s and t are unequal, if yes return false
2. Create Two maps sCount and tCount which will store the character count of both the strings
    a. Example : { 'a': 2, 'n':1}
3. Loop through either s or t string and Push the character count in the map for both s and t string.
4. Check if both the maps are equal once the loop is done.

Time Complexity: O(len(S))

Space Complexity: O(1)

Solution

class Solution:
def isAnagram(self, s: str, t: str) -> bool:
  
  if len(s) != len(t):
    return False
  
  sMap, tMap = {} , {}
  
  for i in range(len(s)):
    sMap[s[i]] = 1+ sMap.get(s[i],0)
    tMap[t[i]] = 1+ tMap.get(t[i],0)
  
  return sMap == tMap
Deepak paramesh
  • 495
  • 1
  • 8
  • 19
  • 1
    Or, to put it another way: `from collections import Counter`, `Counter('python') == Counter('nothyp')` – David Buck May 24 '23 at 15:15
  • Hell yeah... we can definitely go with this solution for a production code. On an interview standpoint, the interviewer is going to expect you to build things from scratch without using library. – Deepak paramesh May 27 '23 at 11:55