[动态规划]1048.最长字符串链

给出一个单词列表,其中每个单词都由小写英文字母组成。如果我们可以在 word1 的任何地方添加一个字母使其变成 word2,那么我们认为 word1 是 word2 的前身。例如,“abc” 是 “abac” 的前身。词链是单词 [word_1, word_2, …, word_k] 组成的序列,k >= 1,其中 word_1 是 word_2的前身,word_2 是 word_3 的前身,依此类推。从给定单词列表 words 中选择单词组成词链,返回词链的最长可能长度。

示例:
输入:[“a”,“b”,“ba”,“bca”,“bda”,“bdca”]
输出:4
解释:最长单词链之一为"a",“ba”,“bda”,“bdca”。

提示:
1 <= words.length <= 1000
1 <= words[i].length <= 16
words[i]仅由小写英文字母组成。

思路:典型的动态规划

  1. 先把words[]中的字符串从短到长排序
  2. 定义dp[],长度为words.legnth(),其中dp[i]表示words[0…i] (从下标0到i)中的最长字符串链。重点dp[i] = max{ dp[j] }+1,其中,j是words[i]的前身下标,j属于{0,…,i-1}。如果words[0…i-1]中不存在words[i]的前身,那么dp[i] = 1
  3. 返回dp[]中的最大值

代码:

//最長字符串鏈
    public int longestStrChain(String[] words) {
        //對words按字符長度 排序
        Arrays.sort(words, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        });
        int[] dp = new int[words.length];
        for(int i=0;i<dp.length;++i){
            int tail = i-1;
            int max = Integer.MIN_VALUE;
            while(tail>=0){
                if(IsChild(words[tail],words[i])){
                    if(dp[tail]>max){
                        max = dp[tail];
                    }
                }
                tail--;
            }
            dp[i] = max==Integer.MIN_VALUE ? 1:max+1;
        }
        Arrays.sort(dp);
        return dp[dp.length-1];

    }

    private boolean IsChild(String child, String father) {
        if(child.length()+1!=father.length())
            return false;
        else{
             char[] ch = child.toCharArray();
             char[] fa = father.toCharArray();
             int pos = fa.length-1; //找到第一個不同的位置
             for(int i=0;i<ch.length;++i){
                 if(fa[i]!=ch[i]){
                     pos = i;
                     break;
                 }
             }
             //將fa[pos]插入ch[i]上
            char[] res = new char[fa.length];
            for(int i=0;i<res.length;++i){
                if(i==pos){
                    res[i] = fa[i];
                }
                else if(i<pos){
                    res[i] = ch[i];
                }else{
                    int j = i-1;
                    res[i] = ch[j];
                }
            }
            String s = String.valueOf(res);
            return s.equals(father);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值