英文原文
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.
中文题目
给出一个单词列表,其中每个单词都由小写英文字母组成。
如果我们可以在 word1
的任何地方添加一个字母使其变成 word2
,那么我们认为 word1
是 word2
的前身。例如,"abc"
是 "abac"
的前身。
词链是单词 [word_1, word_2, ..., word_k]
组成的序列,k >= 1
,其中 word_1
是 word_2
的前身,word_2
是 word_3
的前身,依此类推。
从给定单词列表 words
中选择单词组成词链,返回词链的最长可能长度。
示例:
输入:["a","b","ba","bca","bda","bdca"] 输出:4 解释:最长单词链之一为 "a","ba","bda","bdca"。
提示:
1 <= words.length <= 1000
1 <= words[i].length <= 16
words[i]
仅由小写英文字母组成。
通过代码
高赞题解
1048. 最长字符串链 Medium
方法1:DP
dp[i]
表示从words[0]
到words[i]
最长的词链长度
将字母按字符长度字典序排序的代码
Arrays.sort(words, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
[]public int longestStrChain(String[] words) { Arrays.sort(words, Comparator.comparingInt(String::length)); int n = words.length; int[] dp = new int[n]; int res = 0; for (int i = 0; i < n; i++) { String a = words[i]; for (int j = i + 1; j < n; j++) { String b = words[j]; if (isPredecessor(a, b)) { dp[j] = Math.max(dp[j], dp[i] + 1); res = Math.max(dp[j], res); } } } return res + 1; } /** * 判断a是否是b的前身 是返回true 如 "bda" 是"bdca"的前身 * * @param a * @param b * @return */ private boolean isPredecessor(String a, String b) { int i = 0, j = 0; int m = a.length(), n = b.length(); if ((m + 1) != n) return false; while (i < m && j < n) { if (a.charAt(i) == b.charAt(j)) i++; j++; } return i == m; }
[]print('Hello world!')
方法2:改进版DP
- 根据题意
1 <= words[i].length <= 16
==>arr
存放的是17
个长度的辅助数组,存的是words
的同一字符长度的最末的下标 dp[i]
表示从words[0]
到words[i]
最长的词链长度
[]public int longestStrChain1st(String[] words) { Arrays.sort(words, Comparator.comparingInt(String::length)); int[] arr = new int[17]; Arrays.fill(arr, -1); int n = words.length; for (int i = 0; i < n; i++) { arr[words[i].length()] = i; } int[] dp = new int[n]; Arrays.fill(dp, 1); int res = 0; for (int i = 0; i < n; i++) { int target = words[i].length() - 1; int index = arr[target]; while (index >= 0 && words[index].length() == target) { if (isPredecessor(words[index], words[i])) { dp[i] = Math.max(dp[i], dp[index] + 1); } index--; } res = Math.max(dp[i], res); } return res; }
[]print('Hello world!')
方法3:DFS
[]int res = 0; public int longestStrChain2nd(String[] words) { int min = 0, max = 16;//最小字符长度,最大字符长度 //K为字符长度,Set为该字符长度的word集合 Map<Integer, Set<String>> map = new HashMap<>(); for (String word : words) { map.putIfAbsent(word.length(), new HashSet<>()); map.get(word.length()).add(word); min = Math.min(min, word.length()); max = Math.max(max, word.length()); } for (int len = min; len <= max; len++) { Set<String> curSet = map.get(len); if (curSet == null) continue;//当set没有值时,无需遍历 if ((max + 1 - len <= res)) continue;//最大长度+1-当前的长度<=res,res更加符合题意 for (String cur : curSet) { findNext(map, len, cur); } } return res; } /** * @param map * @param len 当前字符的长度 * @param levelStr 当前字符 */ private void findNext(Map<Integer, Set<String>> map, int len, String levelStr) { res = Math.max(res, levelStr.length() + 1 - len);//记录结果集 Set<String> curSet = map.get(levelStr.length() + 1);// if (curSet == null) return;//退出条件 Iterator<String> it = curSet.iterator(); while (it.hasNext()) { String next = it.next(); if (isPredecessor(levelStr, next)) { findNext(map, len, next); it.remove(); } } }
[]print('Hello world!')
更多内容,欢迎订阅
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
10717 | 23254 | 46.1% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|