Frequency Counter Algorithm in TypeScript

Data Structures and Algorithms for Beginners

ยท

3 min read

A frequency counter is a common technique in solving algorithmic problems, particularly those involving comparing and analyzing patterns within data. It is particularly useful in scenarios where you need to compare two datasets, strings, or arrays and determine if they have the same frequency of elements.

Understanding Frequency Counting

In a frequency counter approach, the idea is to use an object (or a Map in TypeScript) to count the frequency of each distinct element in the input data. The keys of the object or Map represent the unique elements, and the values represent the count of occurrences.

Let's look at a simple example in TypeScript to illustrate a frequency counter for an array:

function createFrequencyCounter(arr: any[]): Record<string, number> {
    const frequencyCounter: Record<string, number> = {};

    for (const element of arr) {
      /* 
        If the element is not in the frequencyCounter,
        add it with a count of 1. Otherwise, increment the count.
      */
      frequencyCounter[element] = (frequencyCounter[element] || 0) + 1;
    }

    return frequencyCounter;
  }

Now, let's see how we can use the frequency counter to solve a problem. Consider the problem of checking whether two arrays have the same frequency of elements:

function sameFrequency(arr1: any[], arr2: any[]): boolean {
    if (arr1.length !== arr2.length) {
      return false;
    }

    const frequencyCounter1 = createFrequencyCounter(arr1);
    const frequencyCounter2 = createFrequencyCounter(arr2);

    // Compare the frequency counters
    for (const key in frequencyCounter1) {
      if (frequencyCounter1[key] !== frequencyCounter2[key]) {
        return false;
      }
    }

    return true;
  }

In this example, sameFrequency uses the createFrequencyCounter function to create frequency counters for both input arrays and then compares them to determine if the arrays have the same frequency of elements.

Benefits of Frequency Counting

Efficiency

The frequency counter approach is often more efficient than nested loops or other brute-force methods, especially when dealing with large datasets.

Readability

It enhances the readability of your code by breaking down the problem into smaller, manageable steps.

Versatility

Frequency counting can be applied to various types of data, such as strings, arrays, or any iterable collection.

Conclusion

Understanding and utilizing frequency counters is a valuable skill in algorithmic problem-solving. It provides an efficient way to compare and analyze patterns within datasets, making it an essential technique in the toolkit of any TypeScript developer dealing with data structures and algorithms.

Practical Example

function createFrequencyCounter(str: string): Record<string, number> {
  const frequencyCounter: Record<string, number> = {};

  for (const char of str) {
    frequencyCounter[char] = (frequencyCounter[char] || 0) + 1;
  }

  return frequencyCounter;
}

function isAnagram(str1: string, str2: string): boolean {
  const frequencyCounter: Record<string, number> = {};

  for (const char of str1) {
    frequencyCounter[char] = (frequencyCounter[char] || 0) + 1;
  }

  for (const char of str2) {
    frequencyCounter[char] = (frequencyCounter[char] || 0) - 1;
  }

  for (const key in frequencyCounter) {
    if (frequencyCounter[key] !== 0) {
      return false;
    }
  }
  return true;
}

Don't miss the chance to boost your TypeScript expertise and discover elegant solutions to complex problems. Explore the blog for a shortcut to algorithmic excellence โ€“ your journey begins here!

ย