3213. 最小代价构造字符串
题目描述:
给你一个目标字符串 target
,一个字符串数组 words
,以及一个对应的花费数组costs
,每个word
对应一个cost
你可以从words
数组中选择任意数量的任意字符串,拼接起来,求拼接成target
的最小花费
如果不能拼成target
则输出-1
1 <= target.length <= 5 * 104
1 <= words.length == costs.length <= 5 * 104
1 <= words[i].length <= target.length
- 所有
words[i].length
的总和小于或等于5 * 104
target
和words[i]
仅由小写英文字母组成。1 <= costs[i] <= 104
思路
考虑动态规划,设状态
状态转移方程:
- 假设
能匹配 到 , - 则状态转移方程为
所以我们需要想个对每个
正解是用后缀数组或者AC自动机来求,不过我不会,我用的字典树进行代替一下,解决匹配问题
但是,字典树最坏的情况会是
class Solution {
public:
int tr[50005][26];
int tot;
int val[50005];
void add(string s, int c){
int root = 0;
for(int i = 0; i < s.size(); ++i){
int id = s[i] - 'a';
if(!tr[root][id])tr[root][id] = ++tot;
root = tr[root][id];
}
if(val[root] == -1)val[root] = c;
else val[root] = min(val[root], c);
}
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
tot = 0;
memset(val, -1,sizeof(val));
for(int i = 0; i < words.size(); ++i)
add(words[i], costs[i]);
vector<int>dp(target.size() + 1, 1e9);
dp[0] = 0;
for(int i = 0; i < target.size(); ++i){
int root = 0;
for(int j = i; j < target.size(); ++j){
int id = target[j] - 'a';
if(tr[root][id] == 0)break;
root = tr[root][id];
if(val[root] != -1){
dp[j + 1] = min(dp[j + 1], dp[i] + val[root]);
}
}
}
if(dp[target.size()] == 1e9)return -1;
else return dp[target.size()];
}
};
还有一种字符串哈希的方法,不过也不是正解
思路是,进行状态转移的时候,我们不是从 words[i].length
的总和小于或等于 50000
,所以最坏情况长度是1 2 3 4….,不同长度的字符串的数量最大是
一个小技巧是,对于“体型”很大的stl结构需要多次遍历时,可以传引用参数,避免每次遍历都要复制一遍,跑的会快一些
比如,for(auto [len, x] : mp)
和 for(auto& [len, x] : mp)
-
for(auto [len, x] : mp)
:这种写法会从容器
mp
中获取每对键值对(key-value pair),并对它们进行复制。也就是说,[len, x]
是对每个元素的拷贝。如果对len
或x
的修改不会影响到容器中原始的值。 -
for(auto& [len, x] : mp)
:这种写法使用引用,因此不会对容器中的元素进行拷贝,而是直接引用容器中的元素。在这种情况下,
[len, x]
是对容器中每个元素的引用。如果在循环体内修改len
或x
,将直接修改容器中相应的值。
class Solution {
public:
const int mod = 1070777777;
const int base = 1331;
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
int n = words.size(), m = target.size();
vector<int>hs(m + 1), mul(m + 1);
mul[0] = 1;
for(int i = 1; i <= m; ++i){
mul[i] = ((long long)mul[i - 1] * base)%mod;
hs[i] = ((long long)hs[i - 1] * base + target[i - 1])%mod;
}
map<int, unordered_map<int, int>>mp;
for(int i = 0; i < n; ++i){
int len = words[i].size();
long long h = 0;
for(int j = 0; j < len; ++j)
h = (h * base + words[i][j])%mod;
if(!mp[len].count(h))
mp[len][h] = costs[i];
else
mp[len][h] = min(mp[len][h], costs[i]);
}
vector<int>dp(m + 1, 1e9);
dp[0] = 0;
for(int i = 1; i <= m; ++i){
for(auto& [len, x] : mp){
int j = i + len - 1;
if(j > m)break;
long long h = ((long long)hs[j] - ((long long)hs[i - 1] * mul[len])%mod + mod) % mod;
if(x.count(h)){
dp[j] = min(dp[j], dp[i - 1] + x[h]);
}
}
}
if(dp[m] == 1e9)return -1;
else return dp[m];
}
};