Skip to content

3045. Count Prefix and Suffix Pairs II

Description

You are given a 0-indexed string array words.

Let's define a boolean function isPrefixAndSuffix that takes two strings, str1 and str2:

  • isPrefixAndSuffix(str1, str2) returns true if str1 is both a and a of str2, and false otherwise.

For example, isPrefixAndSuffix("aba", "ababa") is true because "aba" is a prefix of "ababa" and also a suffix, but isPrefixAndSuffix("abc", "abcd") is false.

Return an integer denoting the number of index pairs (i, j) such that i < j, and isPrefixAndSuffix(words[i], words[j]) is true.

 

Example 1:

Input: words = ["a","aba","ababa","aa"]
Output: 4
Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("a", "aba") is true.
i = 0 and j = 2 because isPrefixAndSuffix("a", "ababa") is true.
i = 0 and j = 3 because isPrefixAndSuffix("a", "aa") is true.
i = 1 and j = 2 because isPrefixAndSuffix("aba", "ababa") is true.
Therefore, the answer is 4.

Example 2:

Input: words = ["pa","papa","ma","mama"]
Output: 2
Explanation: In this example, the counted index pairs are:
i = 0 and j = 1 because isPrefixAndSuffix("pa", "papa") is true.
i = 2 and j = 3 because isPrefixAndSuffix("ma", "mama") is true.
Therefore, the answer is 2.  

Example 3:

Input: words = ["abab","ab"]
Output: 0
Explanation: In this example, the only valid index pair is i = 0 and j = 1, and isPrefixAndSuffix("abab", "ab") is false.
Therefore, the answer is 0.

 

Constraints:

  • 1 <= words.length <= 105
  • 1 <= words[i].length <= 105
  • words[i] consists only of lowercase English letters.
  • The sum of the lengths of all words[i] does not exceed 5 * 105.

 

Solutions

Solution: Trie

  • Time complexity: O(n)
  • Space complexity: O(n)

 

JavaScript

js
/**
 * @param {string[]} words
 * @return {number}
 */
const countPrefixSuffixPairs = function (words) {
  const trie = new Trie();
  let result = 0;

  for (const word of words) {
    result += trie.insert(word);
  }

  return result;
};

class TrieNode {
  constructor() {
    this.children = new Map();
    this.count = 0;
  }
}

class Trie {
  #BASE_CODE = 'a'.charCodeAt(0);

  constructor() {
    this.root = new TrieNode();
  }

  insert(word) {
    const n = word.length;
    let count = 0;
    let node = this.root;

    for (let index = 0; index < n; index++) {
      const prefix = word[index].charCodeAt(0) - this.#BASE_CODE;
      const suffix = word[n - index - 1].charCodeAt(0) - this.#BASE_CODE;
      const hash = prefix * 26 + suffix;

      if (!node.children.has(hash)) {
        node.children.set(hash, new TrieNode());
      }

      node = node.children.get(hash);
      count += node.count;
    }

    node.count += 1;

    return count;
  }
}

Released under the MIT license