前言:这道题和阿里3.20笔试第二题有点像,等这类题熟悉后,去增加那道题的DP写法。
这道题的思路是这样的(摘自别人的blog)
如果想组成链,必须找到一个比当前字符串长度小一的字符串,没有的话,以当前字符为结尾的链长最大只能为1。基于这个思路,
- 我们先建立一个Map lengthMap,用于存储每种长度的字符串有哪些。
- 接下来,再新建一个Map,用来存储以每个字符串为结尾的最长链的长度。
- 然后,从长度为1的字符串开始循环,如果不存在当前字符串长度减一的字符串,那么当前字符串能组成的最大长度为1,将结果保存至map中。如果存在的话,则需要将当前字符串分别按顺序剔除掉一个字符,形成一个子字符串序列,并查看该子序列是否存在于map中,如果存在,该子序列在map中的值再加一即为当前字符串能够组成的一条链的长度,遍历完该字符串所有子序列之后,其中最大值即为以该字符串结尾的最大链长。
- 遍历完所有字符串之后,自然也就得到最大链长是多少。
看不懂思路?那么就去leetcode上debug 跑一遍看一次示例就懂了。
代码
class Solution {
public int longestStrChain(String[] words) {
// 将字符串按照长度分组,并存处于lengthMap 中
Map<Integer, List<String>> lengthMap = new HashMap<>();
int maxlength=0;
for(String word : words){
int length = word.length();
List<String> list = lengthMap.getOrDefault(length, new ArrayList<>());
list.add(word);
lengthMap.put(length, list);
maxlength = Math.max(maxlength, length);
}
// map的key为每个字符串,value为以该字符串结尾的最大链长
Map<String, Integer> map = new HashMap<>();
int res = 1; // 返回结果
for(int i=1;i<=maxlength;i++){
if(!lengthMap.containsKey(i)){ // 如果不存在长度为i的字符串,跳过
continue;
}
List<String> list = lengthMap.get(i); // 取得长度为i的字符串列表
for(String s : list){ // 循环长度为i的字符串
// 如果不存在长度为i-1的字符串
if(!lengthMap.containsKey(i-1)){
map.put(s, 1); // 将当前字符串的链长设置为1
}else{
int count = 1;
for(int j=0;j<i;j++){ // 将当前字符串减掉一个字符
String pre = s.substring(0,j)+s.substring(j+1);
if(map.containsKey(pre)){ // 如果map中存在该序列
// 更新以当前字符串结尾的最大链长
count = Math.max(count, map.get(pre)+1);
}
}
map.put(s, count); // 保存以当前字符串结尾的最大链长
res = Math.max(count, res); // 更新返回结果最大值
}
}
}
return res;
}
}