Skip to content

Latest commit

 

History

History
 
 

1048

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

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 wordA without 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 chain is 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.

Companies: Google, Amazon, Lucid, TikTok, MathWorks, Bloomberg, Facebook, Oracle, ByteDance, Flipkart, Apple, Two Sigma, Wix

Related Topics:
Array, Hash Table, Two Pointers, String, Dynamic Programming

Hints:

  • Instead of adding a character, try deleting a character to form a chain in reverse.
  • For each word in order of length, for each word2 which is word with one character removed, length[word2] = max(length[word2], length[word] + 1).

Solution 1. Top-down DP

For each string, if we check its neighbor by adding a letter, there will be (S + 1) * 26 possible neighbors. If we check its neighbor by removing a letter, there will be S neighbors.

// OJ: https://leetcode.com/problems/longest-string-chain/
// Author: github.com/lzl124631x
// Time: O(N * S^2)
// Space: O(NS)
class Solution {
    unordered_map<string, int> m; 
    int dp(const string &s) {
        if (m[s]) return m[s];
        if (s.size() == 1) return 1;
        int ans = 1;
        for (int i = 0; i < s.size(); ++i) {
            auto copy = s;
            copy.erase(begin(copy) + i);
            if (m.count(copy)) {
                ans = max(ans, 1 + dp(copy));
            }
        }
        return m[s] = ans;
    }
public:
    int longestStrChain(vector<string>& A) {
        for (auto &s : A) m[s] = 0;
        int ans = 0;
        for (auto &s : A) {
            ans = max(ans, dp(s));
        }
        return ans;
    }
};

Solution 2. Bottom-up DP

// OJ: https://leetcode.com/problems/longest-string-chain/
// Author: github.com/lzl124631x
// Time: O(N * S^2)
// Space: O(NS)
class Solution {
public:
    int longestStrChain(vector<string>& A) {
        sort(begin(A), end(A), [](auto &a, auto &b) { return a.size() < b.size(); });
        unordered_map<string, int> dp;
        int ans = 1;
        for (auto &s : A) {
            dp[s] = 1;
            for (int i = 0; i < s.size(); ++i) {
                auto next = s.substr(0, i) + s.substr(i + 1);
                if (dp.count(next)) {
                    dp[s] = max(dp[s], dp[next] + 1);
                    ans = max(ans, dp[s]);
                }
            }
        }
        return ans;
    }
};