You are given an array of words where each word consists of lowercase English letters.
wordA is a predecessor of wordB if and only if we can insert exactly one letter anywhere in wordAwithout changing the order of the other characters to make it equal to wordB.
For example, "abc" is a predecessor of "abac", while "cba" is not a predecessor of "bcad".
A word chainis a sequence of words [word1, word2, ..., wordk] with k >= 1, where word1 is a predecessor of word2, word2 is a predecessor of word3, and so on. A single word is trivially a word chain with k == 1.
Return the length of the longest possible word chain with words chosen from the given list of words.
Example 1:
Input: words = ["a","b","ba","bca","bda","bdca"]
Output: 4
Explanation: One of the longest word chains is ["a","ba","bda","bdca"].
Example 2:
Input: words = ["xbc","pcxbcf","xb","cxbc","pcxbc"]
Output: 5
Explanation: All the words can be put in a word chain ["xb", "xbc", "cxbc", "pcxbc", "pcxbcf"].
Example 3:
Input: words = ["abcd","dbqca"]
Output: 1
Explanation: The trivial word chain ["abcd"] is one of the longest word chains.
["abcd","dbqca"] is not a valid word chain because the ordering of the letters is changed.
Constraints:
1 <= words.length <= 1000
1 <= words[i].length <= 16
words[i] only consists of lowercase English letters.
Solutions
Solution 1: Dynamic Programming
Thinking
A chain grows by one character. \(n\le 1000\) and length \(\le 16\) allow DP after sorting by length. The best chain ending at \(i\) comes from some predecessor \(j\) whose length is one smaller.
Two pointers test whether \(a\) becomes \(b\) by inserting one letter. Each \(i\) tries earlier \(j\) and sets \(f[i]=\max(f[i],f[j]+1)\) on a hit.
The answer is the maximum of \(f\).
First, sort \(\textit{words}\) by string length in ascending order. Define \(f[i]\) as the length of the longest word chain ending with \(\textit{words}[i]\). Initially, \(f[i] = 1\).
For each \(i\), enumerate \(j \in [0, i)\). If \(\textit{words}[j]\) is a predecessor of \(\textit{words}[i]\), update \(f[i] = \max(f[i], f[j] + 1)\). Two strings form a predecessor pair if their lengths differ by \(1\) and the shorter one can be obtained by deleting exactly one character from the longer one.
The answer is \(\max(f)\).
The time complexity is \(O(n^2 \times L)\) and the space complexity is \(O(n)\), where \(n\) is the length of the array and \(L\) is the maximum length of a string.
Solution 1 scans every shorter word even when the length gap is not \(1\). A predecessor is \(w\) with one character deleted, so there are at most \(L\) candidates and a hash map can store scores by word.
Still sorting by length, we delete each index of \(w\) and take \(f[p]+1\). The time becomes \(O(nL^2)\).
Sort \(\textit{words}\) by length as well. Use a hash table \(f\) to record the longest word chain length ending at each word.
For the current word \(w\), enumerate each predecessor \(p\) obtained by deleting one character. If \(p\) is already in the hash table, update \(f[w]\) with \(f[p] + 1\).
The answer is the maximum value among all \(f[w]\).
The time complexity is \(O(n \times L^2)\) and the space complexity is \(O(n \times L)\).