javascriptarraysstringlongest-prefix

Longest prefix that match more than 50% of items in an array


Suppose I have array of strings: ["apple", "ape", "application", "item"]. I need to find the longest common prefix that matches more than 50% of the strings in that array.

For example, we got "ap" being the prefix of 3 strings in a 4 elements array -> so more than 50% of the array -> returns the prefix. This is my attempt:

const longestPrefix = (arrStr) => {
  if (arrStr.length === 0) return "";

  let prefix = "";
  let noPrefixMatched = {};
  // loop the characters of first word
  for (let i = 0; i < arrStr[0].length; i++) {
    let char = arrStr[0][i];
    let j = 0;
    // loop all the words of the array except first one
    for (j = 1; j < arrStr.length; j++) {
      if (arrStr[j][i] !== char) {
        // if first char not matched then set that word as notMatched
        if (i === 0) {
          noPrefixMatched[arrStr[j]] = true;
        }
        break;
      }
      // if the first characters are equal in all words and the loop reach the final word
      if (arrStr[j][i] === char && j === arrStr.length - 1) {
        prefix += char;
      }
    }
  }

  return prefix;
};

I try to get the most common prefix by vertical comparison, but it's not working with a word without any prefix in the array (like "item" in the above array). How should I do this?


Solution

  • One way to do this is to iterate all the words, constructing prefixes one letter at a time and counting the occurrence of each prefix as you see it. You can then filter that result based on the count being greater than 1/2 the length of the input array, and finally sort it by the prefix length descending, returning the first entry in the result:

    const words = ["apple", "ape", "application", "item"]
    
    const counts = words.reduce((acc, w) => {
      prefix = ''
      for (i = 0; i < w.length; i++) {
        prefix += w[i]
        acc[prefix] = (acc[prefix] || 0) + 1
      }
      return acc
    }, {})
    
    const bestPrefix = Object.entries(counts)
      .filter(([_, v]) => v > words.length / 2.0)
      .sort((a, b) => b[0].length - a[0].length)
      [0][0]
      
    console.log(bestPrefix)