diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md new file mode 100644 index 0000000000000..6fa7adf713e91 --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README.md @@ -0,0 +1,380 @@ +--- +comments: true +difficulty: 中等 +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md +--- + + + +# [3253. Construct String with Minimum Cost (Easy) 🔒](https://leetcode.cn/problems/construct-string-with-minimum-cost-easy) + +[English Version](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md) + +## 题目描述 + + + +

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):

+ + + +

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:

+ + +
+ +

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:

+ + + + + +## 解法 + + + +### 方法一:字典树 + 记忆化搜索 + +我们首先创建一个字典树 $\textit{trie}$,字典树的每个节点包含一个长度为 $26$ 的数组 $\textit{children}$,数组中的每个元素都是一个指向下一个节点的指针。字典树的每个节点还包含一个 $\textit{cost}$ 变量,表示从根节点到当前节点的最小花费。 + +我们遍历 $\textit{words}$ 数组,将每个单词插入到字典树中,同时更新每个节点的 $\textit{cost}$ 变量。 + +接下来,我们定义一个记忆化搜索函数 $\textit{dfs}(i)$,表示从 $\textit{target}[i]$ 开始构造字符串的最小花费。那么答案就是 $\textit{dfs}(0)$。 + +函数 $\textit{dfs}(i)$ 的计算过程如下: + +- 如果 $i \geq \textit{len}(\textit{target})$,表示已经构造完整个字符串,返回 $0$。 +- 否则,我们从 $\textit{trie}$ 的根节点开始,遍历 $\textit{target}[i]$ 开始的所有后缀,找到最小花费,即 $\textit{trie}$ 中的 $\textit{cost}$ 变量,加上 $\textit{dfs}(j+1)$ 的结果,其中 $j$ 是 $\textit{target}[i]$ 开始的后缀的结束位置。 + +最后,如果 $\textit{dfs}(0) < \textit{inf}$,返回 $\textit{dfs}(0)$,否则返回 $-1$。 + +时间复杂度 $O(n^2 + L)$,空间复杂度 $O(n + L)$。其中 $n$ 是 $\textit{target}$ 的长度,而 $L$ 是 $\textit{words}$ 数组中所有单词的长度之和。 + + + +#### Python3 + +```python +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 +``` + +#### Java + +```java +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]; + } +} +``` + +#### C++ + +```cpp +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& words, vector& 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; + } +}; +``` + +#### Go + +```go +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 +} +``` + +#### TypeScript + +```ts +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; +} +``` + + + + + + diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md new file mode 100644 index 0000000000000..b5af739ba1c68 --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/README_EN.md @@ -0,0 +1,380 @@ +--- +comments: true +difficulty: Medium +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md +--- + + + +# [3253. Construct String with Minimum Cost (Easy) 🔒](https://leetcode.com/problems/construct-string-with-minimum-cost-easy) + +[中文文档](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md) + +## Description + + + +

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):

+ + + +

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" to s at a cost of 1, resulting in s = "abc".
  • +
  • Select index 2 and append "d" to s at a cost of 1, resulting in s = "abcd".
  • +
  • Select index 4 and append "ef" to s at a cost of 5, resulting in s = "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:

+ + + + + +## Solutions + + + +### Solution 1: Trie + Memoized Search + +We first create a Trie $\textit{trie}$, where each node in the Trie contains an array $\textit{children}$ of length $26$, and each element in the array is a pointer to the next node. Each node in the Trie also contains a $\textit{cost}$ variable, which represents the minimum cost from the root node to the current node. + +We traverse the $\textit{words}$ array, inserting each word into the Trie while updating the $\textit{cost}$ variable for each node. + +Next, we define a memoized search function $\textit{dfs}(i)$, which represents the minimum cost to construct the string starting from $\textit{target}[i]$. The answer is $\textit{dfs}(0)$. + +The calculation process of the function $\textit{dfs}(i)$ is as follows: + +- 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 $\textit{dfs}(0) < \textit{inf}$, return $\textit{dfs}(0)$; otherwise, return $-1$. + +The time complexity is $O(n^2 + L)$, and the space complexity is $O(n + L)$. Here, $n$ is the length of $\textit{target}$, and $L$ is the sum of the lengths of all words in the $\textit{words}$ array. + + + +#### Python3 + +```python +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 +``` + +#### Java + +```java +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]; + } +} +``` + +#### C++ + +```cpp +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& words, vector& 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; + } +}; +``` + +#### Go + +```go +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 +} +``` + +#### TypeScript + +```ts +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; +} +``` + + + + + + diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp new file mode 100644 index 0000000000000..66e33c7b7856c --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.cpp @@ -0,0 +1,53 @@ +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& words, vector& 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; + } +}; diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go new file mode 100644 index 0000000000000..6639a6b37671b --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.go @@ -0,0 +1,56 @@ +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 +} diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java new file mode 100644 index 0000000000000..9f02d21f1c565 --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.java @@ -0,0 +1,53 @@ +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]; + } +} diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py new file mode 100644 index 0000000000000..2619866316b74 --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.py @@ -0,0 +1,36 @@ +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 diff --git a/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts new file mode 100644 index 0000000000000..a0d76bdaa0d2b --- /dev/null +++ b/solution/3200-3299/3253.Construct String with Minimum Cost (Easy)/Solution.ts @@ -0,0 +1,55 @@ +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; +} diff --git a/solution/README.md b/solution/README.md index c9792a8515323..7ba6ac5f01354 100644 --- a/solution/README.md +++ b/solution/README.md @@ -3263,6 +3263,7 @@ | 3250 | [单调数组对的数目 I](/solution/3200-3299/3250.Find%20the%20Count%20of%20Monotonic%20Pairs%20I/README.md) | `数组`,`数学`,`动态规划`,`组合数学`,`前缀和` | 困难 | 第 410 场周赛 | | 3251 | [单调数组对的数目 II](/solution/3200-3299/3251.Find%20the%20Count%20of%20Monotonic%20Pairs%20II/README.md) | `数组`,`数学`,`动态规划`,`组合数学`,`前缀和` | 困难 | 第 410 场周赛 | | 3252 | [英超积分榜排名 II](/solution/3200-3299/3252.Premier%20League%20Table%20Ranking%20II/README.md) | `数据库` | 中等 | 🔒 | +| 3253 | [Construct String with Minimum Cost (Easy)](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md) | | 中等 | 🔒 | ## 版权 diff --git a/solution/README_EN.md b/solution/README_EN.md index 4c818e2d17786..67e8466282339 100644 --- a/solution/README_EN.md +++ b/solution/README_EN.md @@ -3261,6 +3261,7 @@ Press Control + F(or Command + F on | 3250 | [Find the Count of Monotonic Pairs I](/solution/3200-3299/3250.Find%20the%20Count%20of%20Monotonic%20Pairs%20I/README_EN.md) | `Array`,`Math`,`Dynamic Programming`,`Combinatorics`,`Prefix Sum` | Hard | Weekly Contest 410 | | 3251 | [Find the Count of Monotonic Pairs II](/solution/3200-3299/3251.Find%20the%20Count%20of%20Monotonic%20Pairs%20II/README_EN.md) | `Array`,`Math`,`Dynamic Programming`,`Combinatorics`,`Prefix Sum` | Hard | Weekly Contest 410 | | 3252 | [Premier League Table Ranking II](/solution/3200-3299/3252.Premier%20League%20Table%20Ranking%20II/README_EN.md) | `Database` | Medium | 🔒 | +| 3253 | [Construct String with Minimum Cost (Easy)](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md) | | Medium | 🔒 | ## Copyright