最长字符串链

题目描述

给出一个单词数组 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] 仅由小写英文字母组成。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-string-chain
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

如果wordA 是 wordB 的 前身,那么 wordB的长度-wordA的长度=1
将words数组按照字符串长度从小到大排序
动态规划:
dp[i]表示以words[i]结尾的词链的最大长度。
状态转移方程dp[i]=Math.max(dp[j]+1,dp[i])
其中words[j]是words[i]的前身,找到所有words[i]的前身取最大的dp[j]+1就是dp[i]。
返回dp[ ]中的最大值

代码

    public int longestStrChain(String[] words) {
        //按长度从小到大排序
        List<String> list = Arrays.asList(words);
        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                if(o1.length()>o2.length()){
                    return 1;
                }else if(o1.length()==o2.length()){
                    return 0;
                }else{
                    return -1;
                }
            }
        });
        int ans=1;
        int n=list.size();
        int[] dp=new int[n];
        Arrays.fill(dp,1);
        int minLength=list.get(0).length();
        for(int i=1;i<n;i++){
            int length=list.get(i).length();
            if(length==minLength){//说明它本身是最小的长度word,不可能有前身
                dp[i]=1;
            }else{
                int j=i-1;
                while(j>=0 && length-list.get(j).length()<=1){//从它前一个单词开始找它的前身
                	//长度相等跳过
                    if(length-list.get(j).length()==0){
                        j--;
                    }else{
                    	//长度之差为1,判断是否是前身
                        if(judge(list.get(j),list.get(i))){
                            dp[i]=Math.max(dp[j]+1,dp[i]);
                        }
                        j--;
                    }
                }
            }
            ans=Math.max(ans,dp[i]);
        }
        return ans;
    }
    //判断a是否是b的前身
    public boolean judge(String a,String b){
        int n=b.length();
        for(int i=0;i<n-1;i++){
            if(a.charAt(i)!=b.charAt(i)){
                return a.substring(i).equals(b.substring(i+1));
            }
        }
        return true;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值