comments | difficulty | edit_url |
---|---|---|
true |
Medium |
You are given a string target
, an array of strings words
, and an integer array costs
, both arrays of the same length.
Imagine an empty string s
.
You can perform the following operation any number of times (including zero):
- Choose an index
i
in the range[0, words.length - 1]
. - Append
words[i]
tos
. - The cost of operation is
costs[i]
.
Return the minimum cost to make s
equal to target
. If it's not possible, return -1.
Example 1:
Input: target = "abcdef", words = ["abdef","abc","d","def","ef"], costs = [100,1,1,10,5]
Output: 7
Explanation:
The minimum cost can be achieved by performing the following operations:
- Select index 1 and append
"abc"
tos
at a cost of 1, resulting ins = "abc"
. - Select index 2 and append
"d"
tos
at a cost of 1, resulting ins = "abcd"
. - Select index 4 and append
"ef"
tos
at a cost of 5, resulting ins = "abcdef"
.
Example 2:
Input: target = "aaaa", words = ["z","zz","zzz"], costs = [1,10,100]
Output: -1
Explanation:
It is impossible to make s
equal to target
, so we return -1.
Constraints:
1 <= target.length <= 2000
1 <= words.length == costs.length <= 50
1 <= words[i].length <= target.length
target
andwords[i]
consist only of lowercase English letters.1 <= costs[i] <= 105
We first create a Trie
We traverse the
Next, we define a memoized search function
The calculation process of the function
- If
$i \geq \textit{len}(\textit{target})$ , it means the entire string has been constructed, so return$0$ . - Otherwise, we start from the root node of the
$\textit{trie}$ and traverse all suffixes starting from$\textit{target}[i]$ , finding the minimum cost, which is the$\textit{cost}$ variable in the$\textit{trie}$ , plus the result of$\textit{dfs}(j+1)$ , where$j$ is the ending position of the suffix starting from$\textit{target}[i]$ .
Finally, if
The time complexity is
class Trie:
def __init__(self):
self.children: List[Optional[Trie]] = [None] * 26
self.cost = inf
def insert(self, word: str, cost: int):
node = self
for c in word:
idx = ord(c) - ord("a")
if node.children[idx] is None:
node.children[idx] = Trie()
node = node.children[idx]
node.cost = min(node.cost, cost)
class Solution:
def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
@cache
def dfs(i: int) -> int:
if i >= len(target):
return 0
ans = inf
node = trie
for j in range(i, len(target)):
idx = ord(target[j]) - ord("a")
if node.children[idx] is None:
return ans
node = node.children[idx]
ans = min(ans, node.cost + dfs(j + 1))
return ans
trie = Trie()
for word, cost in zip(words, costs):
trie.insert(word, cost)
ans = dfs(0)
return ans if ans < inf else -1
class Trie {
public final int inf = 1 << 29;
public Trie[] children = new Trie[26];
public int cost = inf;
public void insert(String word, int cost) {
Trie node = this;
for (char c : word.toCharArray()) {
int idx = c - 'a';
if (node.children[idx] == null) {
node.children[idx] = new Trie();
}
node = node.children[idx];
}
node.cost = Math.min(node.cost, cost);
}
}
class Solution {
private Trie trie = new Trie();
private char[] target;
private Integer[] f;
public int minimumCost(String target, String[] words, int[] costs) {
for (int i = 0; i < words.length; ++i) {
trie.insert(words[i], costs[i]);
}
this.target = target.toCharArray();
f = new Integer[target.length()];
int ans = dfs(0);
return ans < trie.inf ? ans : -1;
}
private int dfs(int i) {
if (i >= target.length) {
return 0;
}
if (f[i] != null) {
return f[i];
}
f[i] = trie.inf;
Trie node = trie;
for (int j = i; j < target.length; ++j) {
int idx = target[j] - 'a';
if (node.children[idx] == null) {
return f[i];
}
node = node.children[idx];
f[i] = Math.min(f[i], node.cost + dfs(j + 1));
}
return f[i];
}
}
const int inf = 1 << 29;
class Trie {
public:
Trie* children[26]{};
int cost = inf;
void insert(string& word, int cost) {
Trie* node = this;
for (char c : word) {
int idx = c - 'a';
if (!node->children[idx]) {
node->children[idx] = new Trie();
}
node = node->children[idx];
}
node->cost = min(node->cost, cost);
}
};
class Solution {
public:
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
Trie* trie = new Trie();
for (int i = 0; i < words.size(); ++i) {
trie->insert(words[i], costs[i]);
}
int n = target.length();
int f[n];
memset(f, 0, sizeof(f));
auto dfs = [&](auto&& dfs, int i) -> int {
if (i >= n) {
return 0;
}
if (f[i]) {
return f[i];
}
f[i] = inf;
Trie* node = trie;
for (int j = i; j < n; ++j) {
int idx = target[j] - 'a';
if (!node->children[idx]) {
return f[i];
}
node = node->children[idx];
f[i] = min(f[i], node->cost + dfs(dfs, j + 1));
}
return f[i];
};
int ans = dfs(dfs, 0);
return ans < inf ? ans : -1;
}
};
const inf = 1 << 29
type Trie struct {
children [26]*Trie
cost int
}
func NewTrie() *Trie {
return &Trie{cost: inf}
}
func (t *Trie) insert(word string, cost int) {
node := t
for _, c := range word {
idx := c - 'a'
if node.children[idx] == nil {
node.children[idx] = NewTrie()
}
node = node.children[idx]
}
node.cost = min(node.cost, cost)
}
func minimumCost(target string, words []string, costs []int) int {
trie := NewTrie()
for i, word := range words {
trie.insert(word, costs[i])
}
n := len(target)
f := make([]int, n)
var dfs func(int) int
dfs = func(i int) int {
if i >= n {
return 0
}
if f[i] != 0 {
return f[i]
}
f[i] = inf
node := trie
for j := i; j < n; j++ {
idx := target[j] - 'a'
if node.children[idx] == nil {
return f[i]
}
node = node.children[idx]
f[i] = min(f[i], node.cost+dfs(j+1))
}
return f[i]
}
if ans := dfs(0); ans < inf {
return ans
}
return -1
}
const inf = 1 << 29;
class Trie {
children: (Trie | null)[];
cost: number;
constructor() {
this.children = Array(26).fill(null);
this.cost = inf;
}
insert(word: string, cost: number): void {
let node: Trie = this;
for (const c of word) {
const idx = c.charCodeAt(0) - 97;
if (!node.children[idx]) {
node.children[idx] = new Trie();
}
node = node.children[idx]!;
}
node.cost = Math.min(node.cost, cost);
}
}
function minimumCost(target: string, words: string[], costs: number[]): number {
const trie = new Trie();
for (let i = 0; i < words.length; ++i) {
trie.insert(words[i], costs[i]);
}
const n = target.length;
const f: number[] = Array(n).fill(0);
const dfs = (i: number): number => {
if (i >= n) {
return 0;
}
if (f[i]) {
return f[i];
}
f[i] = inf;
let node: Trie | null = trie;
for (let j = i; j < n; ++j) {
const idx = target.charCodeAt(j) - 97;
if (!node?.children[idx]) {
return f[i];
}
node = node.children[idx];
f[i] = Math.min(f[i], node!.cost + dfs(j + 1));
}
return f[i];
};
const ans = dfs(0);
return ans < inf ? ans : -1;
}