【每日一题Day189】LC1048最长字符串链 | dp+排序

该问题通过将单词按长度排序后,使用动态规划求解最长词链。动态规划数组dp[i]表示以words[i]结尾的最长词链长度,遍历比较每个单词的前身并更新dp值,最终返回最大长度。

最长字符串链【LC1048】

给出一个单词数组 words ,其中每个单词都由小写英文字母组成。

如果我们可以 不改变其他字符的顺序 ,在 wordA 的任何地方添加 恰好一个 字母使其变成 wordB ,那么我们认为 wordAwordB前身

  • 例如,"abc""abac"前身 ,而 "cba" 不是 "bcad"前身

词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 1,其中 word1word2 的前身,word2word3 的前身,依此类推。一个单词通常是 k == 1单词链

从给定单词列表 words 中选择单词组成词链,返回 词链的 最长可能长度

到家啦 happy

  • 思路

    某个单词的前身单词的长度一定比该单词少1,因此可以将单词根据长度升序排列。然后通过动态规划找到词链的最长长度,定义dp[i]为以words[i]为词链末尾的最长词链长度,如果words[j]是words[i]的前身,那么判断是否需要更新dp[i]。

  • 实现

    class Solution {
        public int longestStrChain(String[] words) {
            Arrays.sort(words, (o1, o2) -> o1.length() - o2.length());
            int n = words.length;
            int[] dp = new int[n];
            Arrays.fill(dp, 1);
            int res = 0;
            for (int i = 0; i < n; i++){
                for (int j = 0; j < i; j++){
                    if (isPredecessor(words[i], words[j])){
                        dp[i] = Math.max(dp[i], dp[j] + 1);
                    }          
                }
                res = Math.max(res, dp[i]);
            }
            return res;
        }
        // 判断s2是否是s1的前身
        public boolean isPredecessor(String s1, String s2){
            int n = s1.length(), m = s2.length();
            if (n != m + 1) return false;
            int i = 0, j = 0;
            while (i < n && j < m){
                if (s1.charAt(i) == s2.charAt(j)){
                    j++;
                }
                i++;
            }
            return j == m;
        }
    }
    
    • 复杂度

      • 时间复杂度: O ( n l o g n + n 2 L ) O(nlogn+n^2L) O(nlogn+n2L) n n n为数组长度, L L L为字符串的长度,排序需要的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),动态规划的时间复杂度为 O ( n 2 L ) O(n^2L) O(n2L)
      • 空间复杂度: O ( l o g n + n ) O(logn+n) O(logn+n)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值