持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情
一、题目描述:
给出一个单词数组 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 <= words.length <= 1000
- 1 <= words[i].length <= 16
- words[i] 仅由小写英文字母组成。
二、思路分析:
dp[i]定义为以i位置的字符串为词链的最后一个单词可以构成的词链的最大长度。
状态转移方程为dp[i] = max(dp[i], dp[j] + 1)
其中,dp[j]为第i个字符串之前为其前身的字符串可以构成词链的最大长度。
同时对字符串按长度进行排序,保证可以遍历所有的前身。并且定义的dp状态保证了无后效性。
三、AC 代码:
class Solution {
public:
bool isFormer(string a, string b){
int flag = 0;
for(int i = 0, index = 0; i < b.size(); i++, index++){
if(b[i] != a[index]){
if(!flag){
i--;
flag = 1;
}else{
return false;
}
}
}
return true;
}
int longestStrChain(vector<string>& words) {
int len = words.size();
sort(words.begin(), words.end(),[](const string& a, string& b){
return a.size() < b.size();
});
vector<int> dp(len, 1);
for(int i = 0; i < len; i++){
for(int j = 0; j < i; j++){
if(words[j].size() == words[i].size() - 1 && isFormer(words[i], words[j])){
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};