【線性 dp】B014_LC_最長字符串鏈(暴力 / map 優化)

一、Problem

給出一個單詞列表,其中每個單詞都由小寫英文字母組成。

如果我們可以在 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] 僅由小寫英文字母組成。

二、Solution

方法一:dp

  • 定義狀態
    • f[i]f[i] 表示 ws 的前i個單詞形成的最長詞鏈長度
  • 思考初始化:
    • f[0...n]=0f[0...n] = 0
  • 思考狀態轉移方程
    • 如果 ws[i]ws[i]ws[j]ws[j]i<n && i<j(i<n\ \&\&\ i<j) 的前身,則有 f[j]=f[i]+1f[j] = f[i] + 1
  • 思考輸出max(f[0...n])+1max(f[0...n]) + 1
class Solution {
    boolean ck(String a, String b) {
    	int n = a.length(), m = b.length(), i = 0, j = 0;
    	if (n+1 != m)
    		return false;
    	while (i < n && j < m) {
    		if (a.charAt(i) == b.charAt(j))
    			i++;
            j++;
    	}
    	return i == n;
    }
    public int longestStrChain(String[] ws) {
    	Arrays.sort(ws, (s1, s2) -> s1.length() - s2.length());
    	int n = ws.length, max = 0, f[] = new int[n+1];
        
    	for (int i = 0; i < n-1; i++)
		for (int j = i+1; j < n; j++) {
			if (ck(ws[i], ws[j])) {
				f[j] = f[i] + 1;
                max = Math.max(max, f[j]);
            }
		}
		return max + 1;
    }
}

複雜度分析

  • 時間複雜度:O(n2×0n1ws[i].length)O(n^2 × \sum_{0}^{n-1}ws[i].length)
  • 空間複雜度:O(n)O(n)

方法二:map 優化

在方法一中,我們用了兩重循環枚舉一個單詞是否是另一個單詞前身,其實我們只需要枚舉一個字符串的子串(之比源串的字符少 1 的子串)是否出現出現過即可,如果出現過,證明該源串是詞鏈的一部分

class Solution {
    public int longestStrChain(String[] ws) {
    	Arrays.sort(ws, (s1, s2) -> s1.length() - s2.length());
    	int n = ws.length, ans = 0;
    	Map<String, Integer> mp = new HashMap<>();
        
    	for (int i = 0; i < n; i++) {
    		int cur = 0;
    		for (int j = 0; j < ws[i].length(); j++) {
    			String t = ws[i].substring(0, j) + ws[i].substring(j+1, ws[i].length());
    			int c = mp.getOrDefault(t, 0) + 1;
    			cur = Math.max(cur, c);
    		}
    		if (cur > ans)
    			ans = cur;
            mp.put(ws[i], cur);
		}
		return ans;
    }
}

複雜度分析

  • 時間複雜度:O(n×0n1ws[i].length)O(n × \sum_{0}^{n-1} ws[i].length)
  • 空間複雜度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章