we define two words can form a chain: word1 word2, if we can only add one letter to word1 that makes it word2 then they are a chain.
so we are given a list of words, Return the longest possible length of a word chain with words chosen from the given list of words.
sounds a lot like LC1024 which I can’t really think of using DP in this problem.
but since now i do, let’s try to solve it in brute force and then DP.
brute force:
find each and every chain and get the longest chain.
how to find each and every valid chain? we do checking, but the checking will takes us so much time complexity to do that so i don;t think that will do it.
so now let’s try dp:
let’s assume dp[i] is the longest possible length of chain if we only have i words.
if (words[i] and words[j] only difference in one letter, and words[i] is the longer one, so at least we should presort the given words by length of word) dp[i] = dp[j] + 1…in this case we return the last element of dp
or we can assume dp[i] is the longest chain that end with words[i], in this case we return the maximum of dp
but the code is not right, although i believe it’s right idea.
class Solution {
public int longestStrChain(String[] words) {
if (words == null || words.length <= 1) return 0;
int m = words.length;
int[] dp = new int[m + 1];
Arrays.sort(words, (a, b) -> a.length() - b.length());
Arrays.fill(dp, 1);
dp[0] = 0;
for (int i = 1; i <= m; i++) {
for (int j = 0; j < i; j++) {
if (diff(words, i - 1, j)) {
//if word
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
//System.out.println(dp[i]);
}
System.out.println(dp[3]);
System.out.println(dp[4]);
System.out.println(diff(words, 4, 3));
int max = Integer.MIN_VALUE;
for (int i = 0; i <= m; i++) {
max = Math.max(max, dp[i]);
}
return max;
}
private boolean diff(String[] words, int i, int j) {
//i is larger and j is smaller
//so let's check add one letter in words[j] we can get words[i], remember: the original order shouldn't change too
int m = words[i].length();
int n = words[j].length();
if (m - n != 1) {
return false;
}
//now we can sure that the lenngth between those two are one
int s = 0;//pointer on j, because j is the shorter one
int l = 0;
int counter = 0;
while (s < n && l < m) {
if (words[j].charAt(s) != words[i].charAt(l)) {
if (counter > 1) {
return false;
}
counter++;
l++;
} else {
s++;
l++;
}
}
return true;
}
}
有一个更好的时间复杂度的答案
class Solution {
public int longestStrChain(String[] words) {
Map<String, Integer> dp = new HashMap<>();
Arrays.sort(words, (a, b)->a.length() - b.length());
int res = 0;
for (String word : words) {
//for each word we checks every possiblity of its previous in the chain
int best = 0;
for (int i = 0; i < word.length(); ++i) {
String prev = word.substring(0, i) + word.substring(i + 1);
best = Math.max(best, dp.getOrDefault(prev, 0) + 1);
}
dp.put(word, best); //update
res = Math.max(res, best); //get the best from the best
}
return res;
}
}