Count Construct

Updated: 01 February 2024

Problem

Given a target string and a list of strings return the number of ways that the items in the string list can be combined to build the string in the target

An example of what we want to do is:

canConstruct(abcdef, [ab, cd, ef]) = 1
canConstruct(abcdef, [ab, cd]) = 0
canConstruct(abcdef, [ab, cd, cdef, ef]) = 2

In general it will probably be easier to create a shorter string than a longer one

We can consider a base case where:

canConstruct('', [a,b,c]) = true

Base Implementation

The implementation of this is pretty similar to the Can Construct problem

dynamic-programming/memoization/count-construct.ts
export const countConstruct = (target: string, parts: string[]): number => {
  if (target == "") return 1;

  let permutationCount = 0;

  for (let part of parts) {
    if (target.startsWith(part)) {
      const restOfWord = target.slice(part.length);

      const currentCount = countConstruct(restOfWord, parts);
      permutationCount += currentCount;
    }
  }

  return permutationCount;
};

The complexity of this is the same as the Can Construct implementation with a time complexity $O(n^m * m)$ and space complexity of $O(m^2)$

With memoization

We implement the memoization as in the previous examples

dynamic-programming/memoization/count-construct-memo.ts
type Memo = Record<string, number>;

export const countConstruct = (
  target: string,
  parts: string[],
  memo: Memo = {}
): number => {
  if (target in memo) return memo[target];
  if (target == "") return 1;

  let permutationCount = 0;

  for (let part of parts) {
    if (target.startsWith(part)) {
      const restOfWord = target.slice(part.length);

      const currentCount = countConstruct(restOfWord, parts, memo);
      permutationCount += currentCount;
    }
  }

  memo[target] = permutationCount;
  return permutationCount;
};

The complexity of this is the same as the Can Construct memoized implementation with a time complexity $O(n * m^2)$ and space complexity of $O(m^2)$