Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a7c9dd4

Browse files
feat: add solutions to lc problem: No.3253 (doocs#3415)
No.3253.Construct String with Minimum Cost (Easy)
1 parent d8fd6a9 commit a7c9dd4

File tree

9 files changed

+1015
-0
lines changed

9 files changed

+1015
-0
lines changed
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
---
2+
comments: true
3+
difficulty: 中等
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README.md
5+
---
6+
7+
<!-- problem:start -->
8+
9+
# [3253. Construct String with Minimum Cost (Easy) 🔒](https://leetcode.cn/problems/construct-string-with-minimum-cost-easy)
10+
11+
[English Version](/solution/3200-3299/3253.Construct%20String%20with%20Minimum%20Cost%20%28Easy%29/README_EN.md)
12+
13+
## 题目描述
14+
15+
<!-- description:start -->
16+
17+
<p>You are given a string <code>target</code>, an array of strings <code>words</code>, and an integer array <code>costs</code>, both arrays of the same length.</p>
18+
19+
<p>Imagine an empty string <code>s</code>.</p>
20+
21+
<p>You can perform the following operation any number of times (including <strong>zero</strong>):</p>
22+
23+
<ul>
24+
<li>Choose an index <code>i</code> in the range <code>[0, words.length - 1]</code>.</li>
25+
<li>Append <code>words[i]</code> to <code>s</code>.</li>
26+
<li>The cost of operation is <code>costs[i]</code>.</li>
27+
</ul>
28+
29+
<p>Return the <strong>minimum</strong> cost to make <code>s</code> equal to <code>target</code>. If it&#39;s not possible, return -1.</p>
30+
31+
<p>&nbsp;</p>
32+
<p><strong class="example">Example 1:</strong></p>
33+
34+
<div class="example-block">
35+
<p><strong>Input:</strong> <span class="example-io">target = &quot;abcdef&quot;, words = [&quot;abdef&quot;,&quot;abc&quot;,&quot;d&quot;,&quot;def&quot;,&quot;ef&quot;], costs = [100,1,1,10,5]</span></p>
36+
37+
<p><strong>Output:</strong> <span class="example-io">7</span></p>
38+
39+
<p><strong>Explanation:</strong></p>
40+
41+
<p>The minimum cost can be achieved by performing the following operations:</p>
42+
43+
<ul>
44+
<li>Select index 1 and append <code>&quot;abc&quot;</code> to <code>s</code> at a cost of 1, resulting in <code>s = &quot;abc&quot;</code>.</li>
45+
<li>Select index 2 and append <code>&quot;d&quot;</code> to <code>s</code> at a cost of 1, resulting in <code>s = &quot;abcd&quot;</code>.</li>
46+
<li>Select index 4 and append <code>&quot;ef&quot;</code> to <code>s</code> at a cost of 5, resulting in <code>s = &quot;abcdef&quot;</code>.</li>
47+
</ul>
48+
</div>
49+
50+
<p><strong class="example">Example 2:</strong></p>
51+
52+
<div class="example-block">
53+
<p><strong>Input:</strong> <span class="example-io">target = &quot;aaaa&quot;, words = [&quot;z&quot;,&quot;zz&quot;,&quot;zzz&quot;], costs = [1,10,100]</span></p>
54+
55+
<p><strong>Output:</strong> <span class="example-io">-1</span></p>
56+
57+
<p><strong>Explanation:</strong></p>
58+
59+
<p>It is impossible to make <code>s</code> equal to <code>target</code>, so we return -1.</p>
60+
</div>
61+
62+
<p>&nbsp;</p>
63+
<p><strong>Constraints:</strong></p>
64+
65+
<ul>
66+
<li><code>1 &lt;= target.length &lt;= 2000</code></li>
67+
<li><code>1 &lt;= words.length == costs.length &lt;= 50</code></li>
68+
<li><code>1 &lt;= words[i].length &lt;= target.length</code></li>
69+
<li><code>target</code> and <code>words[i]</code> consist only of lowercase English letters.</li>
70+
<li><code>1 &lt;= costs[i] &lt;= 10<sup>5</sup></code></li>
71+
</ul>
72+
73+
<!-- description:end -->
74+
75+
## 解法
76+
77+
<!-- solution:start -->
78+
79+
### 方法一:字典树 + 记忆化搜索
80+
81+
我们首先创建一个字典树 $\textit{trie},ドル字典树的每个节点包含一个长度为 26ドル$ 的数组 $\textit{children},ドル数组中的每个元素都是一个指向下一个节点的指针。字典树的每个节点还包含一个 $\textit{cost}$ 变量,表示从根节点到当前节点的最小花费。
82+
83+
我们遍历 $\textit{words}$ 数组,将每个单词插入到字典树中,同时更新每个节点的 $\textit{cost}$ 变量。
84+
85+
接下来,我们定义一个记忆化搜索函数 $\textit{dfs}(i),ドル表示从 $\textit{target}[i]$ 开始构造字符串的最小花费。那么答案就是 $\textit{dfs}(0)$。
86+
87+
函数 $\textit{dfs}(i)$ 的计算过程如下:
88+
89+
- 如果 $i \geq \textit{len}(\textit{target}),ドル表示已经构造完整个字符串,返回 0ドル$。
90+
- 否则,我们从 $\textit{trie}$ 的根节点开始,遍历 $\textit{target}[i]$ 开始的所有后缀,找到最小花费,即 $\textit{trie}$ 中的 $\textit{cost}$ 变量,加上 $\textit{dfs}(j+1)$ 的结果,其中 $j$ 是 $\textit{target}[i]$ 开始的后缀的结束位置。
91+
92+
最后,如果 $\textit{dfs}(0) < \textit{inf},ドル返回 $\textit{dfs}(0),ドル否则返回 $-1$。
93+
94+
时间复杂度 $O(n^2 + L),ドル空间复杂度 $O(n + L)$。其中 $n$ 是 $\textit{target}$ 的长度,而 $L$ 是 $\textit{words}$ 数组中所有单词的长度之和。
95+
96+
<!-- tabs:start -->
97+
98+
#### Python3
99+
100+
```python
101+
class Trie:
102+
def __init__(self):
103+
self.children: List[Optional[Trie]] = [None] * 26
104+
self.cost = inf
105+
106+
def insert(self, word: str, cost: int):
107+
node = self
108+
for c in word:
109+
idx = ord(c) - ord("a")
110+
if node.children[idx] is None:
111+
node.children[idx] = Trie()
112+
node = node.children[idx]
113+
node.cost = min(node.cost, cost)
114+
115+
116+
class Solution:
117+
def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
118+
@cache
119+
def dfs(i: int) -> int:
120+
if i >= len(target):
121+
return 0
122+
ans = inf
123+
node = trie
124+
for j in range(i, len(target)):
125+
idx = ord(target[j]) - ord("a")
126+
if node.children[idx] is None:
127+
return ans
128+
node = node.children[idx]
129+
ans = min(ans, node.cost + dfs(j + 1))
130+
return ans
131+
132+
trie = Trie()
133+
for word, cost in zip(words, costs):
134+
trie.insert(word, cost)
135+
ans = dfs(0)
136+
return ans if ans < inf else -1
137+
```
138+
139+
#### Java
140+
141+
```java
142+
class Trie {
143+
public final int inf = 1 << 29;
144+
public Trie[] children = new Trie[26];
145+
public int cost = inf;
146+
147+
public void insert(String word, int cost) {
148+
Trie node = this;
149+
for (char c : word.toCharArray()) {
150+
int idx = c - 'a';
151+
if (node.children[idx] == null) {
152+
node.children[idx] = new Trie();
153+
}
154+
node = node.children[idx];
155+
}
156+
node.cost = Math.min(node.cost, cost);
157+
}
158+
}
159+
160+
class Solution {
161+
private Trie trie = new Trie();
162+
private char[] target;
163+
private Integer[] f;
164+
165+
public int minimumCost(String target, String[] words, int[] costs) {
166+
for (int i = 0; i < words.length; ++i) {
167+
trie.insert(words[i], costs[i]);
168+
}
169+
this.target = target.toCharArray();
170+
f = new Integer[target.length()];
171+
int ans = dfs(0);
172+
return ans < trie.inf ? ans : -1;
173+
}
174+
175+
private int dfs(int i) {
176+
if (i >= target.length) {
177+
return 0;
178+
}
179+
if (f[i] != null) {
180+
return f[i];
181+
}
182+
f[i] = trie.inf;
183+
Trie node = trie;
184+
for (int j = i; j < target.length; ++j) {
185+
int idx = target[j] - 'a';
186+
if (node.children[idx] == null) {
187+
return f[i];
188+
}
189+
node = node.children[idx];
190+
f[i] = Math.min(f[i], node.cost + dfs(j + 1));
191+
}
192+
return f[i];
193+
}
194+
}
195+
```
196+
197+
#### C++
198+
199+
```cpp
200+
const int inf = 1 << 29;
201+
202+
class Trie {
203+
public:
204+
Trie* children[26]{};
205+
int cost = inf;
206+
207+
void insert(string& word, int cost) {
208+
Trie* node = this;
209+
for (char c : word) {
210+
int idx = c - 'a';
211+
if (!node->children[idx]) {
212+
node->children[idx] = new Trie();
213+
}
214+
node = node->children[idx];
215+
}
216+
node->cost = min(node->cost, cost);
217+
}
218+
};
219+
220+
class Solution {
221+
public:
222+
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
223+
Trie* trie = new Trie();
224+
for (int i = 0; i < words.size(); ++i) {
225+
trie->insert(words[i], costs[i]);
226+
}
227+
int n = target.length();
228+
int f[n];
229+
memset(f, 0, sizeof(f));
230+
auto dfs = [&](auto&& dfs, int i) -> int {
231+
if (i >= n) {
232+
return 0;
233+
}
234+
if (f[i]) {
235+
return f[i];
236+
}
237+
f[i] = inf;
238+
Trie* node = trie;
239+
for (int j = i; j < n; ++j) {
240+
int idx = target[j] - 'a';
241+
if (!node->children[idx]) {
242+
return f[i];
243+
}
244+
node = node->children[idx];
245+
f[i] = min(f[i], node->cost + dfs(dfs, j + 1));
246+
}
247+
return f[i];
248+
};
249+
int ans = dfs(dfs, 0);
250+
return ans < inf ? ans : -1;
251+
}
252+
};
253+
```
254+
255+
#### Go
256+
257+
```go
258+
const inf = 1 << 29
259+
260+
type Trie struct {
261+
children [26]*Trie
262+
cost int
263+
}
264+
265+
func NewTrie() *Trie {
266+
return &Trie{cost: inf}
267+
}
268+
269+
func (t *Trie) insert(word string, cost int) {
270+
node := t
271+
for _, c := range word {
272+
idx := c - 'a'
273+
if node.children[idx] == nil {
274+
node.children[idx] = NewTrie()
275+
}
276+
node = node.children[idx]
277+
}
278+
node.cost = min(node.cost, cost)
279+
}
280+
281+
func minimumCost(target string, words []string, costs []int) int {
282+
trie := NewTrie()
283+
for i, word := range words {
284+
trie.insert(word, costs[i])
285+
}
286+
287+
n := len(target)
288+
f := make([]int, n)
289+
var dfs func(int) int
290+
dfs = func(i int) int {
291+
if i >= n {
292+
return 0
293+
}
294+
if f[i] != 0 {
295+
return f[i]
296+
}
297+
f[i] = inf
298+
node := trie
299+
for j := i; j < n; j++ {
300+
idx := target[j] - 'a'
301+
if node.children[idx] == nil {
302+
return f[i]
303+
}
304+
node = node.children[idx]
305+
f[i] = min(f[i], node.cost+dfs(j+1))
306+
}
307+
return f[i]
308+
}
309+
if ans := dfs(0); ans < inf {
310+
return ans
311+
}
312+
return -1
313+
}
314+
```
315+
316+
#### TypeScript
317+
318+
```ts
319+
const inf = 1 << 29;
320+
321+
class Trie {
322+
children: (Trie | null)[];
323+
cost: number;
324+
325+
constructor() {
326+
this.children = Array(26).fill(null);
327+
this.cost = inf;
328+
}
329+
330+
insert(word: string, cost: number): void {
331+
let node: Trie = this;
332+
for (const c of word) {
333+
const idx = c.charCodeAt(0) - 97;
334+
if (!node.children[idx]) {
335+
node.children[idx] = new Trie();
336+
}
337+
node = node.children[idx]!;
338+
}
339+
node.cost = Math.min(node.cost, cost);
340+
}
341+
}
342+
343+
function minimumCost(target: string, words: string[], costs: number[]): number {
344+
const trie = new Trie();
345+
for (let i = 0; i < words.length; ++i) {
346+
trie.insert(words[i], costs[i]);
347+
}
348+
349+
const n = target.length;
350+
const f: number[] = Array(n).fill(0);
351+
const dfs = (i: number): number => {
352+
if (i >= n) {
353+
return 0;
354+
}
355+
if (f[i]) {
356+
return f[i];
357+
}
358+
f[i] = inf;
359+
let node: Trie | null = trie;
360+
for (let j = i; j < n; ++j) {
361+
const idx = target.charCodeAt(j) - 97;
362+
if (!node?.children[idx]) {
363+
return f[i];
364+
}
365+
node = node.children[idx];
366+
f[i] = Math.min(f[i], node!.cost + dfs(j + 1));
367+
}
368+
return f[i];
369+
};
370+
371+
const ans = dfs(0);
372+
return ans < inf ? ans : -1;
373+
}
374+
```
375+
376+
<!-- tabs:end -->
377+
378+
<!-- solution:end -->
379+
380+
<!-- problem:end -->

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /