3291. 形成目标字符串需要的最少字符串数 I
给你一个字符串数组 words
和一个字符串 target
。
如果字符串 x
是 words
中 任意 字符串的
前缀
,则认为 x
是一个 有效 字符串。
现计划通过 连接 有效字符串形成 target
,请你计算并返回需要连接的 最少 字符串数量。如果无法通过这种方式形成 target
,则返回 -1
。
示例 1:
输入: words = [“abc”,“aaaaa”,“bcdef”], target = “aabcdabc”
输出: 3
解释:
target 字符串可以通过连接以下有效字符串形成:
words[1]
的长度为 2 的前缀,即 "aa"
。
words[2]
的长度为 3 的前缀,即 "bcd"
。
words[0]
的长度为 3 的前缀,即 "abc"
。
示例 2:
输入: words = [“abababab”,“ab”], target = “ababaababa”
输出: 2
解释:
target 字符串可以通过连接以下有效字符串形成:
words[0]
的长度为 5 的前缀,即 "ababa"
。
words[0]
的长度为 5 的前缀,即 "ababa"
。
示例 3:
输入: words = [“abcdef”], target = “xyz”
输出: -1
提示:
1 <= words.length <= 100
1 <= words[i].length <= 5 * 10^3
- 输入确保
sum(words[i].length) <= 10^5
。
words[i]
只包含小写英文字母。
1 <= target.length <= 5 * 10^3
target
只包含小写英文字母。
字典树+动态规划(记忆化搜索)
超时了,差两个用例
看题解评论区说:
记忆化搜索没有写成递推的话是有这个问题的,主要原因是即便有记忆化,也有多运行的地方,递推不会运行memo的判断和调用。效率有差异。建议写成递推就可以真正n次啦
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 53 54 55 56
| class Trie { class TrieNode { boolean end; TrieNode[] children = new TrieNode[26]; } TrieNode root = new TrieNode(); void insert(String word) { TrieNode cur = root; for (char c : word.toCharArray()) { int index = (int) c - 97; if (cur.children[index] == null) { cur.children[index] = new TrieNode(); } cur = cur.children[index]; } cur.end = true; } boolean search(String word) { TrieNode cur = root; for (char c : word.toCharArray()) { int index = (int) c - 97; if (cur.children[index] == null) return false; cur = cur.children[index]; } return true; } } class Solution { public int minValidStrings(String[] words, String target) { Trie t = new Trie(); for (String word : words) { t.insert(word); } int n = target.length(); int memo[] = new int[n]; Arrays.fill(memo, (int)2e9); int res = dfs(0, t, target, memo); return res >= (int)2e9 ? -1 : res; } private int dfs(int i, Trie t, String target, int memo[]) { int n = target.length(); if (t.search(target.substring(i))) return 1; if (i >= n) return 0; if (memo[i] != (int)2e9) return memo[i]; int res = (int)1e9; Trie.TrieNode cur = t.root; for (int k = i; k < n; k++) { int idx = (int)target.charAt(k)-97; if (cur.children[idx] == null) break; cur = cur.children[idx]; res = Math.min(res, dfs(k+1, t, target, memo) + 1); } return memo[i] = res; } }
|
字典树+动态规划(递推)
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 Trie { class TrieNode { boolean end; TrieNode[] children = new TrieNode[26]; } TrieNode root = new TrieNode(); void insert(String word) { TrieNode cur = root; for (char c : word.toCharArray()) { int index = (int) c - 97; if (cur.children[index] == null) { cur.children[index] = new TrieNode(); } cur = cur.children[index]; } cur.end = true; } int search(String target, int idx) { TrieNode cur = root; int n = target.length(); int cnt = 0; for (int i = idx; i < n; i++) { int index = (int)target.charAt(i) - 97; if (cur.children[index] == null) break; cur = cur.children[index]; cnt++; } return cnt; } } class Solution { public int minValidStrings(String[] words, String target) { Trie t = new Trie(); for (String word : words) { t.insert(word); } int n = target.length(); int f[] = new int[n+1]; Arrays.fill(f, (int)1e9); f[0] = 0; for (int i = 0; i < n; i++) { if (f[i] == (int)1e9) continue; int cnt = t.search(target, i); for (int j = 0; j < cnt && i+1+j <= n; j++) { f[i+1+j] = Math.min(f[i+1+j], f[i] + 1); } } return f[n] == (int)1e9 ? -1 : f[n]; } }
|