这个提示很重要,它限定了字符串的最大长度
题目里并没有说字符串的长度是递增的,有可能是乱序长度排列的,而我的一次错误提交也证实了这一猜想。
那么首先我们应该将字符串按照长度进行聚类,注意这里会用到1 <= words[i].length <= 16
这个条件。可以建立起vector
然后,此题是动态规划类型的题目,那么如何进行动态规划呢?
dp
数组,明确数组值的含义
dp[i]
表示以words[i]
结尾的单词的链的最大长度1
,那么dp[i] = 1
words
数组是乱序的,那么实际上对字符串长度为1
的元素赋初值已经无意义,所以在声明的时候对其全部初始化为1
i
的字符串一定是由长度为i - 1
的字符串演化而来,那么根据聚类表我们就可以得到长度为这两个值的两组字符串。i
这一组里的每一个字符串进行判断,判断在长度为i - 1
这一组里是否有字符串可以通过加一个字母演化成这个字符串i - 1
这组里的字符串的长度,也就是i - 1
再加上1
class Solution {
private:
bool CheckIsPredecessor(string word1, string word2){
if(word1.size() == word2.size()) return false;
size_t i = 0, j = 0;
for(; i < word1.size() && j < word2.size(); i++, j++)
if(word1[i] != word2[j])
break;
return word1 == word2.erase(j, 1);
}
public:
int longestStrChain(vector<string>& words) {
vector<vector<int>> LenDic(17);
for(int i = 0; i < words.size(); i++){
LenDic[words[i].size()].push_back(i);
}
vector<int> dp(words.size(), 1);
int MAX = 1;
for(int i = 2; i < LenDic.size(); i++){
if(!LenDic[i].size() || !LenDic[i - 1].size()) continue;
for(int j = 0; j < LenDic[i].size(); j++){
int LongerIndex, ShorterIndex;
for(int k = 0; k < LenDic[i - 1].size(); k++){
LongerIndex = LenDic[i][j];
ShorterIndex = LenDic[i - 1][k];
if(CheckIsPredecessor(words[ShorterIndex], words[LongerIndex]))
dp[LongerIndex] = max(dp[LongerIndex], dp[ShorterIndex] + 1);
}
MAX = max(MAX, dp[LongerIndex]);
}
}
return MAX;
}
};