comments | difficulty | edit_url | rating | source | tags | ||||
---|---|---|---|---|---|---|---|---|---|
true |
Hard |
2170 |
Weekly Contest 405 Q4 |
|
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 <= 5 * 104
1 <= words.length == costs.length <= 5 * 104
1 <= words[i].length <= target.length
- The total sum of
words[i].length
is less than or equal to5 * 104
. target
andwords[i]
consist only of lowercase English letters.1 <= costs[i] <= 104
We define
For the current
where
The time complexity is
class Solution:
def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
base, mod = 13331, 998244353
n = len(target)
h = [0] * (n + 1)
p = [1] * (n + 1)
for i, c in enumerate(target, 1):
h[i] = (h[i - 1] * base + ord(c)) % mod
p[i] = (p[i - 1] * base) % mod
f = [0] + [inf] * n
ss = sorted(set(map(len, words)))
d = defaultdict(lambda: inf)
min = lambda a, b: a if a < b else b
for w, c in zip(words, costs):
x = 0
for ch in w:
x = (x * base + ord(ch)) % mod
d[x] = min(d[x], c)
for i in range(1, n + 1):
for j in ss:
if j > i:
break
x = (h[i] - h[i - j] * p[j]) % mod
f[i] = min(f[i], f[i - j] + d[x])
return f[n] if f[n] < inf else -1
class Hashing {
private final long[] p;
private final long[] h;
private final long mod;
public Hashing(String word, long base, int mod) {
int n = word.length();
p = new long[n + 1];
h = new long[n + 1];
p[0] = 1;
this.mod = mod;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * base % mod;
h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
}
}
public long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
}
class Solution {
public int minimumCost(String target, String[] words, int[] costs) {
final int base = 13331;
final int mod = 998244353;
final int inf = Integer.MAX_VALUE / 2;
int n = target.length();
Hashing hashing = new Hashing(target, base, mod);
int[] f = new int[n + 1];
Arrays.fill(f, inf);
f[0] = 0;
TreeSet<Integer> ss = new TreeSet<>();
for (String w : words) {
ss.add(w.length());
}
Map<Long, Integer> d = new HashMap<>();
for (int i = 0; i < words.length; i++) {
long x = 0;
for (char c : words[i].toCharArray()) {
x = (x * base + c) % mod;
}
d.merge(x, costs[i], Integer::min);
}
for (int i = 1; i <= n; i++) {
for (int j : ss) {
if (j > i) {
break;
}
long x = hashing.query(i - j + 1, i);
f[i] = Math.min(f[i], f[i - j] + d.getOrDefault(x, inf));
}
}
return f[n] >= inf ? -1 : f[n];
}
}
class Hashing {
private:
vector<long> p, h;
long mod;
public:
Hashing(const string& word, long base, long mod)
: p(word.size() + 1, 1)
, h(word.size() + 1, 0)
, mod(mod) {
for (int i = 1; i <= word.size(); ++i) {
p[i] = p[i - 1] * base % mod;
h[i] = (h[i - 1] * base + word[i - 1]) % mod;
}
}
long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
};
class Solution {
public:
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
const int base = 13331;
const int mod = 998244353;
const int inf = INT_MAX / 2;
int n = target.size();
Hashing hashing(target, base, mod);
vector<int> f(n + 1, inf);
f[0] = 0;
set<int> ss;
for (const string& w : words) {
ss.insert(w.size());
}
unordered_map<long, int> d;
for (int i = 0; i < words.size(); ++i) {
long x = 0;
for (char c : words[i]) {
x = (x * base + c) % mod;
}
d[x] = d.find(x) == d.end() ? costs[i] : min(d[x], costs[i]);
}
for (int i = 1; i <= n; ++i) {
for (int j : ss) {
if (j > i) {
break;
}
long x = hashing.query(i - j + 1, i);
if (d.contains(x)) {
f[i] = min(f[i], f[i - j] + d[x]);
}
}
}
return f[n] >= inf ? -1 : f[n];
}
};
type Hashing struct {
p []int64
h []int64
mod int64
}
func NewHashing(word string, base, mod int64) *Hashing {
n := len(word)
p := make([]int64, n+1)
h := make([]int64, n+1)
p[0] = 1
for i := 1; i <= n; i++ {
p[i] = p[i-1] * base % mod
h[i] = (h[i-1]*base + int64(word[i-1])) % mod
}
return &Hashing{p, h, mod}
}
func (hs *Hashing) query(l, r int) int64 {
return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
}
func minimumCost(target string, words []string, costs []int) int {
const base = 13331
const mod = 998244353
const inf = math.MaxInt32 / 2
n := len(target)
hashing := NewHashing(target, base, mod)
f := make([]int, n+1)
for i := range f {
f[i] = inf
}
f[0] = 0
ss := make(map[int]struct{})
for _, w := range words {
ss[len(w)] = struct{}{}
}
lengths := make([]int, 0, len(ss))
for length := range ss {
lengths = append(lengths, length)
}
sort.Ints(lengths)
d := make(map[int64]int)
for i, w := range words {
var x int64
for _, c := range w {
x = (x*base + int64(c)) % mod
}
if existingCost, exists := d[x]; exists {
if costs[i] < existingCost {
d[x] = costs[i]
}
} else {
d[x] = costs[i]
}
}
for i := 1; i <= n; i++ {
for _, j := range lengths {
if j > i {
break
}
x := hashing.query(i-j+1, i)
if cost, ok := d[x]; ok {
f[i] = min(f[i], f[i-j]+cost)
}
}
}
if f[n] >= inf {
return -1
}
return f[n]
}