最长字符串链

1048. 最长字符串链

题目描述

给出一个单词数组 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、首先将所给的串按照从短到长进行排序,然后将相同长度的串加入到对应的二维数组中去

2、将最短的串的dp值初始化为1

3、循环查找比当前串长度少一的串,如果是其前身则,dp[当前串] = max(dp[当前串] ,dp[前身]+1)

4、返回最大的dp值即可

class Solution {
public:
    static bool cmp(string s1, string s2){
        return s1.length() < s2.size();
    }
    //比较函数,如果s1 是 s2的前身则返回true,否则返回false
    bool count(string s1,string s2){
        int i = 0 , j = 0;
        while(i < s1.length() && j <s2.length()){
            if(s1[i] == s2[i+j]){
                i++;
            }else{
                j++;
            }
            if(j > 1){
                return false;
            }
        }
        return true;
    }
    int longestStrChain(vector<string>& w) {
        int ans = 1;
        sort(w.begin(),w.end(),cmp);
        int len = w.size();
        //mp数组将 不同长度的串分类
        unordered_map<int,vector<string>> mp(17);
        vector<int>dp(len+1);
        mp[w[0].size()].push_back(w[0]);
        for(int i = 1 ; i < len ;i++){
                mp[w[i].size()].push_back(w[i]);
        }
        int x = 0,tp = 1,tmax = 1;
        while(x < len){
            //tp 用于加速查找,如果找到前身的最大值,则停止查找
            tp = tmax;
            int leng = mp[w[x].size()].size();
            //初始化
            if(x == 0){
                for(int j =  0 ; j < mp[w[x].size()].size();j++){
                    dp[j] = 1;
                }
            }else{
                for(int j =  0 ; j < leng ;j++){
                    dp[x+j] = 1;
                    for(int i = x-1;i >= 0;i--){
                    //在长度等于当前串长度减一的串中寻找,如果能找到前
                    //身,则当前串的dp值为 dp[前身]+1;否则当前串的值为 1
                        if( w[i].size() < w[x+j].size()-1){
                            break;
                        }else if(count(w[i],w[x+j])){
                            //找到前身
                            dp[x+j] = max(dp[x+j],dp[i]+1);
                            if(dp[x+j] > ans){
                                //更新返回值
                                ans = dp[x+j];
                            }
                            //更新当前层的最大值
                            if(tmax < dp[x+j]){
                                tmax = dp[x+j];
                            }
                            //如果前身的dp值,为当前串的所有可能的前身中值最大的,则跳出循环
                            if(dp[x+j] == tp+1){
                                break;
                            }
                        }
                    }
                }
            }
            x += leng;
        }
        // for(auto h : dp){
        //     cout<<h<<" ";
        // }
        // cout<<endl;
        return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值