leetcode
leetcode 1001 ~ 1050
最长字符串链

最长字符串链

难度:

标签:

题目描述

代码结果

运行时间: 68 ms, 内存: 16.3 MB


/*
 * 使用Java Stream的实现思路:
 * 1. 依然是先对单词进行排序。
 * 2. 使用一个HashMap记录每个单词的最长链长度。
 * 3. 使用Stream API来遍历每个单词,计算每个单词的最长链长度。
 * 4. 使用Optional来获取最长链的最大值。
 */

import java.util.*;
import java.util.stream.*;

public class LongestStringChainStream {
    public int longestStrChain(String[] words) {
        Arrays.sort(words, Comparator.comparingInt(String::length));
        Map<String, Integer> dp = new HashMap<>();
        return Arrays.stream(words)
                .map(word -> {
                    int currentLength = IntStream.range(0, word.length())
                            .mapToObj(i -> new StringBuilder(word).deleteCharAt(i).toString())
                            .mapToInt(predecessor -> dp.getOrDefault(predecessor, 0) + 1)
                            .max().orElse(1);
                    dp.put(word, currentLength);
                    return currentLength;
                })
                .max(Integer::compareTo)
                .orElse(1);
    }
}

解释

方法:

此题解采用动态规划的思想,核心是用哈希表d记录每个单词长度对应的单词列表,同时使用哈希表mp存储到当前单词为止可能形成的最长字符串链的长度。首先,将单词按长度分类并存入d中,并记录最长单词的长度maxd。接着,从最长单词长度开始,向下查找可能的前身单词。如果长度为fad的单词能通过删除一个字符得到长度为fad-1的单词,则更新该前身单词在mp中的值。整个过程从最大长度递减到1,每次尝试通过删除操作找到可能的前身,并更新最长链的长度。

时间复杂度:

O(N*fad^2)

空间复杂度:

O(N)

代码细节讲解

🦆
题解中提到了通过删除一个字符来寻找单词的前身,如何确保删除的过程中不会漏掉某些可能的前身单词?
为了确保在删除字符的过程中不漏掉任何可能的前身单词,算法对每个单词尝试删除其每个位置上的字符。具体来说,对长度为 fad 的单词 wf,算法会依次删除从第一个字符到最后一个字符,生成 fad-1 长度的所有可能单词,并检查这些单词是否存在于单词列表中。这种方法通过遍历单词的每个字符位置并尝试删除,确保了考虑了所有可能的删除方式。
🦆
题解中使用了两个哈希表d和mp,能否具体解释一下这两个哈希表在算法中具体扮演的角色是什么?
在题解中,哈希表 d 用于存储按长度分类的单词列表。这样可以快速访问特定长度的所有单词,从而在检查可能的前身单词时提高效率。哈希表 mp 用来存储每个单词对应的最长字符串链的长度。它记录了从当前单词开始,可以向前追溯形成的最长字符串链的长度,这样在检查新的单词时可以快速更新其可能的最长前身链长度。
🦆
对于每个单词,题解中提到尝试删除其每个位置的字符,这种方法是否存在效率上的问题,特别是当单词长度非常长时?
尝试删除每个位置的字符确实可能导致效率问题,特别是当单词长度非常长时。对于一个长度为 n 的单词,这种方法需要进行 n 次操作来生成所有可能的前身单词,并且每次操作都需要检查新生成的单词是否存在于单词列表中,这可能导致较高的时间复杂度。尽管如此,由于单词长度通常有限,这种方法在实际应用中可能仍然是可行的,但对于极端情况确实需要考虑更高效的算法。
🦆
题解计算最长字符串链时,是如何确保通过删除字符得到的新单词确实存在于单词列表中的?
题解通过使用集合 child 来确保通过删除字符得到的新单词确实存在于单词列表中。在处理特定长度的单词时,会创建一个集合 child,其中包含所有长度为 fad-1 的单词。然后,对于每个长度为 fad 的单词,通过删除字符生成新单词后,会检查这个新单词是否存在于 child 集合中。这种方法利用集合的快速查找功能,有效确保了只有存在于单词列表中的前身才会被计入最长字符串链的计算。

相关问题