Counting matching substrings in JavaScript

Counting matching substrings in JavaScript is essential for text analysis and string manipulation tasks. This article explores different methods to count subsequences within a string, helping developers choose the most appropriate approach for their needs.

Problem Statement

We need a JavaScript function that counts subsequences in a given string. The function takes a string "str" and an array of strings "arr" as input. It examines each element in "arr" and determines how many strings are subsequences of "str".

A subsequence is formed by removing characters from the original string while maintaining the relative order of remaining characters.

Sample Input:

str = 'abracadabra';
arr = ['a', 'bra', 'cad', 'dab'];

Sample Output:

Output = 4;

Explanation: All elements in the array ('a', 'bra', 'cad', 'dab') are subsequences of 'abracadabra', so the count is 4.

Method 1: Brute-Force Approach

This approach generates all possible subsequences of the input string and checks if each exists in the target array. While comprehensive, it's computationally expensive for larger inputs.

function countSubsequences(str, arr) {
   let count = 0;
 
   // Generate all possible subsequences of the input string
   function generateSubsequences(sub, index) {
      if (index === str.length) {
         // Check if the subsequence exists in the array
         if (arr.includes(sub)) {
            count++;
         }
         return;
      }
 
      // Include the current character in the subsequence
      generateSubsequences(sub + str[index], index + 1);
 
      // Exclude the current character from the subsequence
      generateSubsequences(sub, index + 1);
   }
 
   // Start generating subsequences from the beginning of the string
   generateSubsequences("", 0);
 
   return count;
}
 
// Example usage:
const str = "abcde";
const arr = ["a", "ab", "bd", "abc", "acde", "eab"];
const result = countSubsequences(str, arr);
console.log(result);
5

Method 2: Two-Pointer Approach

This more efficient approach uses two pointers to traverse the target string and each candidate subsequence. It's faster because it doesn't generate all possible subsequences upfront.

function countValidSubsequences(arr, target) {
   let count = 0;
 
   for (let i = 0; i < arr.length; i++) {
      const current = arr[i];
      let j = 0; // pointer for current string
      let k = 0; // pointer for target string
 
      while (j < current.length && k < target.length) {
         if (current[j] === target[k]) {
            j++; // move both pointers when characters match
            k++;
         } else {
            k++; // only move target pointer when no match
         }
      }
 
      // If we've matched all characters in current string
      if (j === current.length) {
         count++;
      }
   }
 
   return count;
}
 
// Example usage: 
const str = "abcde"; 
const arr = ["a", "ab", "bd", "abc", "acde", "eab"]; 
const result = countValidSubsequences(arr, str); 
console.log(result);
5

Comparison

Method Time Complexity Space Complexity Best For
Brute-Force O(2^n * m) O(2^n) Small strings
Two-Pointer O(n * m) O(1) Large datasets

Conclusion

The two-pointer approach is generally preferred for its efficiency and lower memory usage. Use the brute-force method only when dealing with very small strings or when you need to generate all subsequences for other purposes.

Updated on: 2026-03-15T23:19:00+05:30

243 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements