leetcode 1048. Longest String Chain

题目概述

解题思路

我刚看到这题的时候,想到的思路就是把每个字符串当成一个节点,判断两个点之间是否存在联线,然后构建出一个有向图(森林);然后对所有入度为零的节点去求最长的路径。

这个方法实现起来就比较复杂,所以我参考了他人解法:

有个老哥用了动态规划来求解这道题。他用一个一维的数组dp存储以各个元素为链尾时,链的最长长度。我们首先按照字符串的长度,对原始的字符串vector重新排序。然后对第i个字符串,我们只需要遍历一下在它之前的字符串(长度不超过它),对那些长度比它少一的串,做一下比较,看下当前串是否是该串的后续串即可。如果是的话,就可以比较&更新dp[i]的值。我先实现了一版这个方法,不过它险些超时。。。它慢的地方或许在于,每次遍历字符串做比较耗时太久,假设字符串平均长度为S,则时间复杂度是O(N^2*S)。

接下来我参考了另一个老哥的思路——它用map来存储这个dp数组,最漂亮的地方在于,它的字符串比较函数是通过hash实现的:只需要对当前的字符串words[i]做拆分,然后每次删去其中的一个字符,得到余下的子串,在hash map里面检查这个子串是否存在,如果存在,则dp[i]检查一下是否需要更新。这时,时间复杂度就是O(N*S)。

方法性能

第一种方法的性能:

第二种方法的性能:

示例代码

第一种方法:

class Solution {
public:
    static bool cmp(string A, string B)
    {
        return A.size() < B.size();
    }
    
    bool isNeigh(string A, string B)
    {
        if(A.size() + 1 != B.size())
            return false;
        int sta = 0, delta = 0;
        while(sta + delta < B.size())
        {
            if(A[sta] == B[sta + delta])
                sta++;
            else
                delta++;
        }
        return delta == 1 ? true : false;
            
    }
    
    int longestStrChain(vector<string>& words) 
    {
        int len_w = words.size(), max_len = 0;
        vector<int> dp(len_w, 1);
        sort(words.begin(), words.end(), cmp);
        
        for(int i = 0; i < len_w; ++i)
        {
            for(int j = 0; j < i; ++j)
            {
                if(isNeigh(words[j], words[i]))
                {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
            max_len = max(max_len, dp[i]);
        }
        
        return max_len;
    }
};

第二种方法:

class Solution {
public:
    static bool cmp(const string &A, const string &B)
    {
        return A.size() < B.size();
    }
    
    int longestStrChain(vector<string>& words) 
    {
        int len_w = words.size(), max_len = 0;
        unordered_map<string, int> Sub;
        sort(words.begin(), words.end(), cmp);
        for(int i = 0; i < len_w; ++i)
            Sub[words[i]] = 1;
        
        for(int i = 0; i < len_w; ++i)
        {
            string temp_w = words[i];
            for( int wi = 0; wi < temp_w.size(); ++wi)
            {
                string subs = temp_w.substr(0, wi) + temp_w.substr(wi + 1, temp_w.size() - wi);
                if(Sub.find(subs) != Sub.end())
                {
                    Sub[temp_w] = max(Sub[temp_w], Sub[subs] + 1);
                }
            }
            
            max_len = max(max_len, Sub[temp_w]);
        }
        
        return max_len;
    }
};

这次学到的一个知识点是:如何定义一些常见的容器的比较函数。一种写法就是:

static bool cmp(const type A, const type B)
{
    .....;
    return xxx;
}

然后在排序时,调用:

sort(a, a + len, cmp);

或者:

priority_queue<type, cmp> test;

另一个点是,解决这种题目常用的思路是动态规划。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值