GuilinDev

Lc1048

05 August 2008

1048. Longest String Chain

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

wordA 是 wordB 的前身当且仅当我们可以在 wordA 的任意位置准确插入一个字母而不改变其他字符的顺序以使其等于 wordB。

例如,“abc”是“abac”的前身,而“cba”不是“bcad”的前身。 一个词链是一个词序列 [word1, word2, …, wordk],其中 k >= 1,其中 word1 是 word2 的前身,word2 是 word3 的前身,以此类推。单个单词通常是具有 k == 1 的单词链。

返回从给定单词列表中选择的单词的最长可能单词链的长度。

不用排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {
    public int longestStrChain(String[] words) {
        List<Set<String>> wordLen = new ArrayList(16);
        Map<String, Integer> lengthMap = new HashMap();
        
        int result = 1;
        for(int i = 0; i < 16; ++i) {
            wordLen.add(new HashSet<String>());
        }
        
        for(String word : words) {
            int len = word.length();
            wordLen.get(len - 1).add(word);
        }
        
        
        for(int i = 1; i < wordLen.size(); ++i) {
            Set<String> currLength = wordLen.get(i);
            if(currLength.isEmpty()) {
                continue;
            }
            Set<String> prevLength = wordLen.get(i - 1);
            if(prevLength.isEmpty()) {
                continue;
            }
            for(String word : currLength) {
                int len = word.length();
                int max = 0;
                for(int j = 0; j < len; ++j) {
                    String sub = word.substring(0, j) + word.substring(j + 1);
                    if(prevLength.contains(sub)) {
                        max = Math.max(max, lengthMap.getOrDefault(sub, 1) + 1);
                    }
                }
                if(max != 0) {
                    result = Math.max(result, max);
                    lengthMap.put(word, max);
                }
            }
            
        }
        
        return result;
    }
}

DP + sorting

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Solution {

    public int longestStrChain(String[] words) {
        var n = words.length;
        Arrays.sort(words, (a, b) -> a.length() - b.length());

        var nextRangeIdx = new int[n];
        nextRangeIdx[n - 1] = n;
        for (int i = n - 2; i >= 0; i--)
            nextRangeIdx[i] = words[i].length() == words[i + 1].length()
                    ? nextRangeIdx[i + 1]
                    : i + 1;

        var dp = new int[words.length];
        for (int curIdx = n - 1; curIdx >= 0; curIdx--) {
            var curWord = words[curIdx];
            var nextIdx = nextRangeIdx[curIdx];
            var maxSeq = 1;
            while (nextIdx < words.length && curWord.length() + 1 == words[nextIdx].length()) {
                if (predecessor(curWord, words[nextIdx]))
                    maxSeq = Math.max(maxSeq, dp[nextIdx] + 1);
                nextIdx++;
            }
            dp[curIdx] = maxSeq;
        }

        var max = 0;
        for (int len : dp)
            if (len > max)
                max = len;

        return max;
    }

    boolean predecessor(String pre, String cur) {
        var p = 0;
        var c = 0;
        var inserted = false;
        while (p < pre.length() && c < cur.length()) {
            if (pre.charAt(p) == cur.charAt(c)) {
                p++;
            } else {
                if (inserted)
                    return false;
                inserted = true;
            }
            c++;
        }

        return true;
    }
}