题目来源: 1048. 最长字符串链
题目描述:
- 描述: 给出一个单词数组 words ,其中每个单词都由小写英文字母组成。 如果我们可以 不改变其他字符的顺序 ,在 wordA 的任何地方添加 恰好一个 字母使其变成 wordB ,那么我们认为 wordA 是 wordB 的 前身 。 例如,"abc" 是 "abac" 的 前身 ,而 "cba" 不是 "bcad" 的 前身 词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 1,其中 word1 是 word2 的前身,word2 是 word3 的前身,依此类推。一个单词通常是 k == 1 的 单词链 。 从给定单词列表 words 中选择单词组成词链,返回 词链的 最长可能长度 。
- 示例:
示例1:
输入:words = ["a","b","ba","bca","bda","bdca"]
输出:4
- 解释:最长单词链之一为 ["a","ba","bda","bdca"]
示例2:
输入:words = ["xbc","pcxbcf","xb","cxbc","pcxbc"]
输出:5
- 解释:所有的单词都可以放入单词链 ["xb", "xbc", "cxbc", "pcxbc", "pcxbcf"]
示例3:
输入:words = ["abcd","dbqca"]
输出:1
- 解释:字链["abcd"]是最长的字链之一。 ["abcd","dbqca"]不是一个有效的单词链,因为字母的顺序被改变了。
思路
思路1 根据题意可知,对于字符串「前身」的定义为:不改变其他字符的顺序 ,在wordA 的任何地方添加恰好一个字母使其变成wordB,那么我们认为wordA 是wordB 的前身。 将wordB 中去掉任意一个字母,其余字符保持不变构成的字符串即为wordB 的前身。 因此对于每个字符串s,假设其所有的前身s′为结尾的最长链的长度为l,即可知道以s 为结尾的最长链的长度为l+1。为保证我们求s 的最长链时,其所有的前身的最长链的长度均已求出,需要将所有的字符串按照长度大小进行排序。假设字符串s 最长链的长度为cnt(s) 的前身为则此时可以知道 根据以上结论,实际计算过程如下:
- 首先对字符串数组words 按照字符串长度的大小进行排序;
- 依次遍历每个字符串words[i],并初始以words[i] 为结尾的最长链的长度cnt[words[i]] 为1;
- 依次尝试去掉words[i] 中的每个字符,并构成其可能的前身prev,在哈希表cnt 查找prev 对应的最长链长度,如果cnt+1 大于cnt[words[i]],则更新cnt[words[i]];
- 最终返回可能的最长链的长度即可。
具体实现1
class Solution {
public int longestStrChain(String[] words) {
Map<String, Integer> cnt = new HashMap<String, Integer>();
Arrays.sort(words, (a, b) -> a.length() - b.length());
int res = 0;
for (String word : words) {
cnt.put(word, 1);
for (int i = 0; i < word.length(); i++) {
String prev = word.substring(0, i) + word.substring(i + 1);
if (cnt.containsKey(prev)) {
cnt.put(word, Math.max(cnt.get(word), cnt.get(prev) + 1));
}
}
res = Math.max(res, cnt.get(word));
}
return res;
}
}
复杂度分析1:
- 时间复杂度O(n×m×(logn+m))
- 空间复杂度:O(n×m)