Open In App

Count Occurrences of Anagrams

Improve
Improve
Like Article
Like
Save
Share
Report

Given a word and a text, return the count of the occurrences of anagrams of the word in the text(For eg: anagrams of word for are for, ofr, rof etc.))

Examples: 

Input : forxxorfxdofr
            for
Output : 3
Explanation : Anagrams of the word for – for, orf, ofr appear in the text and hence the count is 3.

Input : aabaabaa
            aaba
Output : 4
Explanation : Anagrams of the word aaba – aaba, abaa each appear twice in the text and hence the count is 4.

A simple approach is to traverse from start of the string considering substrings of length equal to the length of the given word and then check if this substring has all the characters of word.

Implementation:

C++




// A Simple C++ program to count anagrams of a
// pattern in a text.
#include<bits/stdc++.h>
using namespace std;
 
// Function to find if two strings are equal
bool areAnagram(string s1, string s2)
{
    map<char, int> m;
    for(int i = 0; i < s1.length(); i++)
        m[s1[i]]++;
         
    for(int i = 0; i < s2.length(); i++)
        m[s2[i]]--;
         
    for(auto it = m.begin(); it != m.end(); it++)
        if(it -> second != 0)
            return false;
             
        return true;
}
 
int countAnagrams(string text, string word)
{
     
    // Initialize result
    int res = 0;
    for(int i = 0;
            i < text.length() - word.length() + 1;
            i++)
    {
         
        // Check if the word and substring are
        // anagram of each other.
        if (areAnagram(text.substr(i, word.length()),
                                      word))
            res++;
    }
    return res;
}
 
// Driver Code
int main()
{
    string text = "forxxorfxdofr";
    string word = "for";
     
    cout << countAnagrams(text, word);
     
    return 0;
}
 
// This code is contributed by probinsah


Java




// A Simple Java program to count anagrams of a
// pattern in a text.
import java.io.*;
import java.util.*;
 
public class GFG {
 
    // Function to find if two strings are equal
    static boolean araAnagram(String s1,
                              String s2)
    {
        // converting strings to char arrays
        char[] ch1 = s1.toCharArray();
        char[] ch2 = s2.toCharArray();
 
        // sorting both char arrays
        Arrays.sort(ch1);
        Arrays.sort(ch2);
 
        // Check for equality of strings
        if (Arrays.equals(ch1, ch2))
            return true;
        else
            return false;
    }
 
    static int countAnagrams(String text, String word)
    {
        int N = text.length();
        int n = word.length();
 
        // Initialize result
        int res = 0;
 
        for (int i = 0; i <= N - n; i++) {
 
            String s = text.substring(i, i + n);
 
            // Check if the word and substring are
            // anagram of each other.
            if (araAnagram(word, s))
                res++;
        }
     
        return res;
    }
 
    // Driver code
    public static void main(String args[])
    {
        String text = "forxxorfxdofr";
        String word = "for";
        System.out.print(countAnagrams(text, word));
    }
}


Python3




# A Simple Python program to count anagrams of a
# pattern in a text.
 
# Function to find if two strings are equal
def areAnagram(s1, s2):
    m = {}
    for i in range(len(s1)):
        if s1[i] not in m:
            m[s1[i]] = 1
        else:
            cnt = m[s1[i]]
            m.pop(s1[i])
            m[s1[i]] = cnt + 1
 
    for j in range(len(s2)):
        if((s2[j] in m) == False):
            return False
        else:
            cnt = m[s2[j]]
            m.pop(s2[j])
            m[s2[j]] = cnt - 1
         
    for it in m.values():
       if(it != 0):
          return False
    return True
 
def countAnagrams(text, word):
     
    # Initialize result
    res = 0
    for i in range(len(text)- len(word)+1):
         
        # Check if the word and substring are
        # anagram of each other.
 
        if (areAnagram(text[i:i+len(word)], word)):
            res += 1
    return res
 
# Driver Code
 
text = "forxxorfxdofr"
word = "for"
     
print(countAnagrams(text, word))
 
# This code is contributed by shinjanpatra


C#




// C# program to count anagrams of a
// pattern in a text.
using System;
using System.Collections.Generic;
 
class GFG {
 
    // Function to find if two strings are equal
    static bool areAnagram(string first, string second)
    {
        if (first.Length != second.Length)
            return false;
 
        if (first == second)
            return true; // or false: Don't know whether a
                         // string counts as an anagram of
                         // itself
 
        Dictionary<char, int> pool
            = new Dictionary<char, int>();
        foreach(
            char element in first
                .ToCharArray()) // fill the dictionary with
                                // that available chars and
                                // count them up
        {
            if (pool.ContainsKey(element))
                pool[element]++;
            else
                pool.Add(element, 1);
        }
        foreach(char element in second
                    .ToCharArray()) // take them out again
        {
            if (!pool.ContainsKey(
                    element)) // if a char isn't there at
                              // all; we're out
                return false;
            if (--pool[element]
                == 0) // if a count is less than zero after
                      // decrement; we're out
                pool.Remove(element);
        }
        return pool.Count == 0;
    }
 
    static int countAnagrams(string text, string word)
    {
        int N = text.Length;
        int n = word.Length;
 
        // Initialize result
        int res = 0;
 
        for (int i = 0; i <= N - n; i++) {
 
            string s = text.Substring(i, n);
 
            // Check if the word and substring are
            // anagram of each other.
            if (areAnagram(word, s) == true) {
                res++;
            }
        }
 
        return res;
    }
 
    // Driver code
    public static void Main()
    {
        string text = "forxxorfxdofr";
        string word = "for";
        Console.Write(countAnagrams(text, word));
    }
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript




<script>// A Simple JavaScript program to count anagrams of a
// pattern in a text.
 
// Function to find if two strings are equal
function areAnagram(s1, s2)
{
    let m = new Map();
    for(let i = 0; i < s1.length ; i++)
    {
        if(m.has(s1[i])===false){
            m.set(s1[i],1)
        }
        else{
            let cnt = m.get(s1[i]);
            m.delete(s1[i]);
            m.set(s1[i],cnt+1);
        }
    }
 
    for(let j = 0; j < s1.length; j++)
    {
        if(m.has(s2[j])===false){
            return false;
        }
        else{
            let cnt = m.get(s2[j]);
            m.delete(s2[j]);
            m.set(s2[j],cnt-1);
        }
    }
         
    for(const it in m.values()){
       if(it !== 0)return false
    }
    return true;
}
 
function countAnagrams(text, word)
{
     
    // Initialize result
    let res = 0;
    for(let i = 0;i < text.length - word.length + 1;i++)
    {
         
        // Check if the word and substring are
        // anagram of each other.
 
        if (areAnagram(text.substring(i, i+word.length), word)) res++;
    }
    return res;
}
 
// Driver Code
 
let text = "forxxorfxdofr";
let word = "for";
     
document.write(countAnagrams(text, word));
 
// This code is contributed by shinjanpatra
</script>


Output

3
















Complexity Analysis:

  • Time Complexity: O(l1logl1 + l2logl2)
  • Auxiliary space: O(l1 + l2). 

An Efficient Solution is to use a count array to check for anagrams, we can construct the current count window from the previous window in O(1) time using the sliding window concept. 

Implementation:

C++




#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    static int findAnagrams(const std::string& text,
                            const std::string& word)
    {
        int text_length = text.length();
        int word_length = word.length();
        if (text_length < 0 || word_length < 0
            || text_length < word_length)
            return 0;
 
        constexpr int CHARACTERS = 256;
        int count = 0;
        int index = 0;
        std::array<char, CHARACTERS> wordArr;
        wordArr.fill(0);
        std::array<char, CHARACTERS> textArr;
        textArr.fill(0);
 
        // till window size
        for (; index < word_length; index++) {
            wordArr[CHARACTERS - word[index]]++;
            textArr[CHARACTERS - text[index]]++;
        }
        if (wordArr == textArr)
            count += 1;
        // next window
        for (; index < text_length; index++) {
            textArr[CHARACTERS - text[index]]++;
            textArr[CHARACTERS
                    - text[index - word_length]]--;
 
            if (wordArr == textArr)
                count += 1;
        }
        return count;
    }
};
 
int main()
{
    const std::string& text = "forxxorfxdofr";
    const std::string& word = "for";
 
    cout << Solution::findAnagrams(text, word);
    return 0;
}


Java




// An efficient Java program to count anagrams of a
// pattern in a text.
import java.io.*;
import java.util.*;
 
class Solution {
    public static int countAnagrams(String s, String p)
    {
        // change CHARACTERS to support range of supported
        // characters
        int CHARACTERS = 256;
        int sn = s.length();
        int pn = p.length();
        int count = 0;
        if (sn < 0 || pn < 0 || sn < pn)
            return 0;
 
        char[] pArr = new char[CHARACTERS];
        char[] sArr = new char[CHARACTERS];
        int i = 0;
        // till window size
        for (; i < pn; i++) {
            sArr[CHARACTERS - s.charAt(i)]++;
            pArr[CHARACTERS - p.charAt(i)]++;
        }
        if (Arrays.equals(pArr, sArr))
            count += 1;
        // next window
        for (; i < sn; i++) {
            sArr[CHARACTERS - s.charAt(i)]++;
            sArr[CHARACTERS - s.charAt(i - pn)]--;
 
            if (Arrays.equals(pArr, sArr))
                count += 1;
        }
        return count;
    }
    // Driver code
    public static void main(String args[])
    {
        String text = "forxxorfxdofr";
        String word = "for";
        System.out.print(countAnagrams(text, word));
    }
}


Python3




# A Simple Python program to count anagrams of a
# pattern in a text with the help of sliding window problem
string = "forxxorfxdofr"
ptr = "for"
n = len(string)
k = len(ptr)
d = {}
for i in ptr:
    if i in d:
        d[i] += 1
    else:
        d[i] = 1
i = 0
j = 0
count = len(d)
 
ans = 0
 
 
while j < n:
    if string[j] in d:
        d[string[j]] -= 1
        if d[string[j]] == 0:
            count -= 1
    if (j-i+1) < k:
        j += 1
    elif (j-i+1) == k:
        if count == 0:
            ans += 1
 
        if string[i] in d:
            d[string[i]] += 1
            if d[string[i]] == 1:
                count += 1
 
        i += 1
        j += 1
print(ans)


C#




// An efficient C# program to count anagrams of a
// pattern in a text.
using System;
using System.Linq;
 
class Solution
{
    public static int FindAnagrams(string text, string word)
    {
        int textLength = text.Length;
        int wordLength = word.Length;
        if (textLength < 0 || wordLength < 0 || textLength < wordLength)
            return 0;
         // change CHARACTERS to support range of supported
        // characters
        const int CHARACTERS = 256;
        int count = 0;
        int index = 0;
        char[] wordArr = new char[CHARACTERS];
        Array.Fill(wordArr, (char)0);
        char[] textArr = new char[CHARACTERS];
        Array.Fill(textArr, (char)0);
 
        // till window size
        for (; index < wordLength; index++)
        {
            wordArr[CHARACTERS - word[index]]++;
            textArr[CHARACTERS - text[index]]++;
        }
        if (wordArr.SequenceEqual(textArr))
            count += 1;
        // next window
        for (; index < textLength; index++)
        {
            textArr[CHARACTERS - text[index]]++;
            textArr[CHARACTERS - text[index - wordLength]]--;
 
            if (wordArr.SequenceEqual(textArr))
                count += 1;
        }
        return count;
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        string text = "forxxorfxdofr";
        string word = "for";
 
        Console.WriteLine(Solution.FindAnagrams(text, word));
    }
}
//This code is contributed by rudra1807raj


Javascript




<script>
 
// A Simple JavaScript program to count anagrams of a
// pattern in a text with the help of sliding window problem
 
let string = "forxxorfxdofr"
let ptr = "for"
let n = string.length
let k = ptr.length
let temp = []
let d = new Map();
for(let i = 0; i < ptr.length; i++)
{
    if(d.has(ptr[i]))
        d.set(ptr[i], d.get(ptr[i])+1)
    else
        d.set(ptr[i], 1)
}
 
let i = 0
let j = 0
let count = d.size
 
let ans = 0
 
while(j < n)
{
    if(d.has(string[j]))
    {
        d.set(string[j], d.get(string[j]) - 1)
        if(d.get(string[j]) == 0)
            count--
    }
    if(j - i + 1 < k)
        j++
    else if(j - i + 1 == k){
        if(count == 0)
            ans++
 
        if(d.has(string[i]))
        {
            d.set(string[i],d.get(string[i])+1)
            if(d.get(string[i]) == 1)
                count++
        }
        i++
        j++
    }
}
 
document.write(ans)
 
// This code is contributed by shinjanpatra
 
</script>


Output

3
















Complexity Analysis:

  • Time Complexity: O(l1 + l2)
  • Auxiliary space: O(l1 + l2). 

Another Approach:

  • Create an empty frequency map of characters in the word we are looking for.
  • Populate the frequency map created in step 1 with the frequency of each character in the word we are looking for.
  • Initialize a frequency map for the current window of characters in the text.
  • Initialize a count variable to keep track of the number of anagrams found.
  • Use a sliding window approach to iterate over the text.
  • At each iteration, add the current character to the frequency map for the window and remove the character that went out of the window.
  • Compare the frequency maps of the word and the window to check if they are equal.
  • If the frequency maps are equal, increment the count of anagrams found.
  • Return the count of anagrams found.

Below is the implementation of the above approach:

C++




#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
 
int countAnagrams(string text, string word)
{
    int n = text.size(), m = word.size();
    unordered_map<char, int> freqWord, freqText;
    int count = 0;
 
    // Create frequency map of characters in the word
    for (char c : word)
        freqWord++;
 
    // Sliding window approach
    for (int i = 0; i < n; i++) {
        // Add character to frequency map
        freqText]++;
 
        // Remove character that went out of window
        if (i >= m) {
            if (freqText] == 1)
                freqText.erase(text[i - m]);
            else
                freqText]--;
        }
 
        // Compare frequency maps
        if (i >= m - 1 && freqText == freqWord)
            count++;
    }
 
    return count;
}
 
int main()
{
    string text = "forxxorfxdofr";
    string word = "for";
    cout << countAnagrams(text, word) << endl;
 
    return 0;
}
// This code is contributed by rudra1807raj


Java




import java.util.HashMap;
import java.util.Map;
 
public class Main {
 
    public static int countAnagrams(String text, String word) {
        int n = text.length();
        int m = word.length();
        Map<Character, Integer> freqWord = new HashMap<>();
        Map<Character, Integer> freqText = new HashMap<>();
        int count = 0;
 
        // Create frequency map of characters in the word
        for (char c : word.toCharArray()) {
            freqWord.put(c, freqWord.getOrDefault(c, 0) + 1);
        }
 
        // Sliding window approach
        for (int i = 0; i < n; i++) {
            // Add character to frequency map
            char currentChar = text.charAt(i);
            freqText.put(currentChar, freqText.getOrDefault(currentChar, 0) + 1);
 
            // Remove character that went out of the window
            if (i >= m) {
                char removedChar = text.charAt(i - m);
                if (freqText.get(removedChar) == 1) {
                    freqText.remove(removedChar);
                } else {
                    freqText.put(removedChar, freqText.get(removedChar) - 1);
                }
            }
 
            // Compare frequency maps
            if (i >= m - 1 && freqText.equals(freqWord)) {
                count++;
            }
        }
 
        return count;
    }
 
    public static void main(String[] args) {
        String text = "forxxorfxdofr";
        String word = "for";
        System.out.println(countAnagrams(text, word));
    }
}


Python3




# Python code for the above approach
def countAnagrams(text, word):
    n = len(text)
    m = len(word)
    freqWord = {}
    freqText = {}
    count = 0
 
    # Create frequency map of characters in the word
    for c in word:
        freqWord = freqWord.get(c, 0) + 1
 
    # Sliding window approach
    for i in range(n):
        # Add character to frequency map
        freqText] = freqText.get(text[i], 0) + 1
 
        # Remove character that went out of window
        if i >= m:
            if freqText] == 1:
                del freqText]
            else:
                freqText] -= 1
 
        # Compare frequency maps
        if i >= m - 1 and freqText == freqWord:
            count += 1
 
    return count
 
# Driver code
text = "forxxorfxdofr"
word = "for"
print(countAnagrams(text, word))
# THIS CODE IS CONTRIBUTED BY PIYUSH AGARWAL


C#




using System;
using System.Collections.Generic;
 
class Program
{
    static int CountAnagrams(string text, string word)
    {
        int n = text.Length;
        int m = word.Length;
        Dictionary<char, int> freqWord = new Dictionary<char, int>();
        Dictionary<char, int> freqText = new Dictionary<char, int>();
        int count = 0;
 
        // Create frequency map of characters in the word
        foreach (char c in word)
        {
            if (freqWord.ContainsKey(c))
                freqWord++;
            else
                freqWord = 1;
        }
 
        // Sliding window approach
        for (int i = 0; i < n; i++)
        {
            // Add character to frequency map
            if (freqText.ContainsKey(text[i]))
                freqText]++;
            else
                freqText] = 1;
 
            // Remove character that went out of window
            if (i >= m)
            {
                char charToRemove = text[i - m];
                if (freqText[charToRemove] == 1)
                    freqText.Remove(charToRemove);
                else
                    freqText[charToRemove]--;
            }
 
            // Compare frequency maps
            if (i >= m - 1 && AreDictionariesEqual(freqText, freqWord))
                count++;
        }
 
        return count;
    }
 
    // Helper function to compare two dictionaries for equality
    static bool AreDictionariesEqual(Dictionary<char, int> dict1, Dictionary<char, int> dict2)
    {
        if (dict1.Count != dict2.Count)
            return false;
 
        foreach (var kvp in dict1)
        {
            char key = kvp.Key;
            int value = kvp.Value;
 
            if (!dict2.ContainsKey(key) || dict2[key] != value)
                return false;
        }
 
        return true;
    }
 
    // Driver Code
    static void Main()
    {
        string text = "forxxorfxdofr";
        string word = "for";
        Console.WriteLine(CountAnagrams(text, word));
    }
}


Javascript




function countAnagrams(text, word) {
  const n = text.length;
  const m = word.length;
  const freqWord = new Map();
  const freqText = new Map();
  let count = 0;
 
  // Create frequency map of characters in the word
  for (const c of word) {
    freqWord.set(c, (freqWord.get(c) || 0) + 1);
  }
 
  // Sliding window approach
  for (let i = 0; i < n; i++) {
    // Add character to frequency map
    freqText.set(text[i], (freqText.get(text[i]) || 0) + 1);
 
    // Remove character that went out of window
    if (i >= m) {
      const prevChar = text[i - m];
      const prevFreq = freqText.get(prevChar);
      if (prevFreq === 1) {
        freqText.delete(prevChar);
      } else {
        freqText.set(prevChar, prevFreq - 1);
      }
    }
 
    // Compare frequency maps
    if (i >= m - 1 && compareMaps(freqText, freqWord)) {
      count++;
    }
  }
 
  return count;
}
 
function compareMaps(map1, map2) {
  if (map1.size !== map2.size) {
    return false;
  }
  for (const [key, value] of map1) {
    if (value !== map2.get(key)) {
      return false;
    }
  }
  return true;
}
 
const text = "forxxorfxdofr";
const word = "for";
console.log(countAnagrams(text, word));
 
// THIS CODE IS CONTRIBUTED BY KIRTI AGARWAL


Output

3

















Time Complexity: O(n), where n is the length of the text. This is because we only iterate over the text once and use constant time operations for each iteration. 

Auxiliary Space: O(k), where k is the size of the frequency map of the word. This is because we only need to store the frequency maps of the word and the window at any given time.

Please suggest if someone has a better solution that is more efficient in terms of space and time.
This article is contributed by Aarti_Rathi.



Last Updated : 02 Dec, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads