|
| 1 | +/** |
| 2 | + * @param {string[]} words |
| 3 | + * @return {number[]} |
| 4 | + */ |
| 5 | +const longestCommonPrefix = (words) => { |
| 6 | + const n = words.length |
| 7 | + const ans = new Array(n).fill(0) |
| 8 | + if (n < 2) { |
| 9 | + return ans // all zeros |
| 10 | + } |
| 11 | + // compute lcp of each adjacent pair |
| 12 | + const lcp = new Array(n - 1) |
| 13 | + for (let i = 0; i < n - 1; i++) { |
| 14 | + lcp[i] = commonPrefixLen(words[i], words[i + 1]) |
| 15 | + } |
| 16 | + // prefix max and suffix max of lcp[] |
| 17 | + const preMax = new Array(n - 1) |
| 18 | + const sufMax = new Array(n - 1) |
| 19 | + for (let i = 0; i < n - 1; i++) { |
| 20 | + preMax[i] = i === 0 ? lcp[i] : Math.max(preMax[i - 1], lcp[i]) |
| 21 | + } |
| 22 | + for (let i = n - 2; i >= 0; i--) { |
| 23 | + sufMax[i] = i === n - 2 ? lcp[i] : Math.max(sufMax[i + 1], lcp[i]) |
| 24 | + } |
| 25 | + // for each removal index k |
| 26 | + for (let k = 0; k < n; k++) { |
| 27 | + let leftMax = 0, |
| 28 | + rightMax = 0 |
| 29 | + // lcp[0..k-2] |
| 30 | + if (k - 2 >= 0) leftMax = preMax[k - 2] |
| 31 | + // lcp[k+1..n-2] |
| 32 | + if (k + 1 <= n - 2) rightMax = sufMax[k + 1] |
| 33 | + let best = Math.max(leftMax, rightMax) |
| 34 | + // if removal creates a new adjacent pair between k-1 and k+1 |
| 35 | + if (k > 0 && k < n - 1) { |
| 36 | + const c = commonPrefixLen(words[k - 1], words[k + 1]) |
| 37 | + best = Math.max(best, c) |
| 38 | + } |
| 39 | + ans[k] = best |
| 40 | + } |
| 41 | + return ans |
| 42 | +} |
| 43 | + |
| 44 | +function commonPrefixLen(a, b) { |
| 45 | + const m = Math.min(a.length, b.length) |
| 46 | + let i = 0 |
| 47 | + while (i < m && a.charAt(i) === b.charAt(i)) { |
| 48 | + i++ |
| 49 | + } |
| 50 | + return i |
| 51 | +} |
0 commit comments