Algorithms

Introduction to Knowing What to Track

2 min read
Data StructuresAlgorithmsPatternsFrequency CountingHashMapJavaScript

Many algorithm problems boil down to one question: what should I track? I kept noticing that solutions often involved counting frequencies, tracking seen elements, or monitoring counts. This "knowing what to track" pattern has become one of my most useful problem-solving tools.

The Pattern

The idea is simple: count frequencies, then use that information to solve the problem. It has two phases:

  1. Counting Phase: Iterate through data and count how often each element appears
  2. Utilization Phase: Use the frequency information to solve the problem

When I Use This Pattern

I've found this pattern useful when:

  • I need to find the most/least frequent element
  • I need to check if elements appear a certain number of times
  • I need to compare frequencies between datasets
  • I need to detect patterns in the data

Examples from My Problems

Finding Duplicates: I used frequency counting to find if an array has duplicates:

function hasDuplicate(nums) {
  const counts = {};

  // Counting phase
  for (let num of nums) {
    counts[num] = (counts[num] || 0) + 1;
  }

  // Utilization phase
  for (let num in counts) {
    if (counts[num] > 1) {
      return true; // Found a duplicate!
    }
  }
  return false;
}

Checking Permutations: I used it to check if two strings are permutations of each other:

function arePermutations(str1, str2) {
  if (str1.length !== str2.length) return false;

  const counts = {};

  // Count characters in first string
  for (let char of str1) {
    counts[char] = (counts[char] || 0) + 1;
  }

  // Decrement for second string
  for (let char of str2) {
    if (!counts[char]) return false;
    counts[char]--;
  }

  // All should be zero if they're permutations
  return Object.values(counts).every((count) => count === 0);
}

Data Structures I Use

Hash Maps: Most common choice. I use the element as key and frequency as value:

const frequency = {};
for (let item of data) {
  frequency[item] = (frequency[item] || 0) + 1;
}

Arrays: When elements are small integers, I use array indices:

const frequency = new Array(26).fill(0); // For lowercase letters
for (let char of str) {
  frequency[char.charCodeAt(0) - "a".charCodeAt(0)]++;
}

What I Learned

This pattern has become one of my go-to approaches. The key is recognizing when frequency information is what I need. Once I identify that, the solution often becomes straightforward.

Key Takeaways

  • Frequency counting is a powerful problem-solving pattern
  • It has two phases: counting and utilization
  • Hash maps are usually the best data structure for this
  • Recognizing when to use this pattern is a valuable skill

I've found that many problems become easier once I identify what I need to track. This pattern has helped me solve problems I initially thought were complex. I hope recognizing this pattern helps you too!

Share:
Loading reactions...

Loading comments...