LeetCode-1048:最长字符串链

一、题目描述

LeetCode-1048:最长字符串链_第1张图片

二、解题思路

这个提示很重要,它限定了字符串的最大长度
题目里并没有说字符串的长度是递增的,有可能是乱序长度排列的,而我的一次错误提交也证实了这一猜想。
那么首先我们应该将字符串按照长度进行聚类,注意这里会用到1 <= words[i].length <= 16这个条件。可以建立起vector> LenDic(17)
然后,此题是动态规划类型的题目,那么如何进行动态规划呢?

  • 确定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;
    }
};

四、运行结果

LeetCode-1048:最长字符串链_第2张图片

你可能感兴趣的:(LeetCode,动态规划,字符串,字符串,聚类,leetcode,动态规划)