class Solution:
def longestStrChain(self, words):
words.sort(key=len)
dp = {}
max_chain = 1
for word in words:
dp[word] = 1
for i in range(len(word)):
prev = word[:i] + word[i+1:]
if prev in dp:
dp[word] = max(dp[word], dp[prev] + 1)
max_chain = max(max_chain, dp[word])
return max_chain
class Solution {
public:
int longestStrChain(vector<string>& words) {
sort(words.begin(), words.end(), [](const string &a, const string &b) {
return a.size() < b.size();
});
unordered_map<string, int> dp;
int maxChain = 1;
for (const string &word : words) {
dp[word] = 1;
for (int i = 0; i < word.size(); ++i) {
string prev = word.substr(0, i) + word.substr(i + 1);
if (dp.count(prev)) {
dp[word] = max(dp[word], dp[prev] + 1);
}
}
maxChain = max(maxChain, dp[word]);
}
return maxChain;
}
};
class Solution {
public int longestStrChain(String[] words) {
Arrays.sort(words, (a, b) -> a.length() - b.length());
Map<String, Integer> dp = new HashMap<>();
int maxChain = 1;
for (String word : words) {
dp.put(word, 1);
for (int i = 0; i < word.length(); i++) {
String prev = word.substring(0, i) + word.substring(i + 1);
if (dp.containsKey(prev)) {
dp.put(word, Math.max(dp.get(word), dp.get(prev) + 1));
}
}
maxChain = Math.max(maxChain, dp.get(word));
}
return maxChain;
}
}
var longestStrChain = function(words) {
words.sort((a, b) => a.length - b.length);
const dp = {};
let maxChain = 1;
for (const word of words) {
dp[word] = 1;
for (let i = 0; i < word.length; i++) {
const prev = word.slice(0, i) + word.slice(i + 1);
if (dp[prev] !== undefined) {
dp[word] = Math.max(dp[word], dp[prev] + 1);
}
}
maxChain = Math.max(maxChain, dp[word]);
}
return maxChain;
};
Given a list of strings words
, you are to find the length of the longest possible "string chain". A string chain is a sequence of words where each word is formed by adding exactly one letter to the previous word in the chain, and all words in the chain must be present in the original list words
.
For example, starting with "a", you can form "ba" by adding 'b', and from "ba" you can form "bda" by adding 'd', if all these words are in words
. The goal is to find the maximum length of such a chain.
The function should return an integer representing the length of the longest chain.
At first glance, this problem might suggest trying all possible sequences of words, checking if each can be formed by adding one letter at a time. However, this brute-force approach would be extremely inefficient, especially as the number of words grows.
Instead, we can notice that for any word, its possible predecessor in a chain is any word formed by removing exactly one letter. So, if we process shorter words first, we can build up the longest chain ending at each word by checking all possible predecessors.
This leads us to a dynamic programming approach: for each word, we store the length of the longest chain ending at that word, and for each word, we look for all its possible predecessors by removing each character in turn. This optimization avoids redundant calculations and leverages the structure of the problem.
The algorithm can be broken down into the following steps:
dp
where dp[word]
is the length of the longest chain ending at word
.
dp
, we update the chain length for the current word to be the maximum of its current value or the predecessor's chain length plus one.
This approach is efficient because it ensures that every possible predecessor has already been processed before its longer forms.
Let's consider the sample input: ["a", "b", "ba", "bca", "bda", "bdca"]
["a", "b", "ba", "bca", "bda", "bdca"]
The Longest String Chain problem can be efficiently solved using dynamic programming and a hash map. By processing words from shortest to longest and building chains by removing one letter at a time, we avoid redundant calculations and ensure optimal substructure. This approach transforms a potentially exponential brute-force search into a polynomial-time solution, making it both elegant and practical for large datasets.