当前位置:网站首页>贴纸拼词 —— 记忆化搜索 / 状压DP
贴纸拼词 —— 记忆化搜索 / 状压DP
2022-08-04 00:56:00 【小酒窝.】
https://leetcode.cn/problems/stickers-to-spell-word/
题意
给定一个长度为 n 的字符串 S,给定 m 种字符串 a[],每种字符串无限个。
现在要选出一些字符串,将其每个字符剪切后可以拼接成字符串 S。
问,最少要选多少个字符串?
1 ≤ n ≤ 15 , 1 ≤ m ≤ 50 , 1 ≤ ∣ a i ∣ ≤ 10 1 \le n \le 15,\ 1 \le m \le 50,\ 1 \le |a_i| \le 10 1≤n≤15, 1≤m≤50, 1≤∣ai∣≤10
思路
目标字符串长度很小,考虑记忆化搜索:
对于当前的字符串 s 来说,选择一个字符串 t,将 s 中能由字符串 t 剪切得到的位置删掉后得到新串,然后递归到这个新串。
如果当前串为空,说明到了终点,返回 0。
否则,返回 m 个新串到达终点的答案的最小值 + 1。
为了方便转移,可以将长度最大为 15 的串进行状态压缩,对于某一位来说如果是 1 说明没删,如果是 0 说明删掉了,状压成一个整数。
class Solution {
public:
string aim;
int x, ans = 1e9;
vector<string> st;
int f[1<<15];
int cnt[60][30];
int tcnt[30];
void pre()
{
for(int i=0;i<st.size();i++)
{
string s = st[i];
for(char c : s) cnt[i][c-'a']++;
}
}
int dfs(int x)
{
int sum = 1e9;
if(x == 0) return 0;
for(int i=0;i<st.size();i++)
{
for(int j=0;j<26;j++) tcnt[j] = cnt[i][j];
int tx = x;
for(int j=0;j<15;j++) //遍历所有位置,将能用串 i 删掉的位置都删掉
{
if(!(x >> j & 1)) continue;
char c = aim[j];
if(tcnt[c - 'a']) tcnt[c - 'a']--, tx -= 1<<j;
}
if(tx == x) continue; //如果串无变化不再递归当前值,否则会陷入循环
if(!f[tx]) dfs(tx); //剪枝
sum = min(sum, f[tx] + 1); //递归到新串
}
f[x] = sum; //记忆化
return sum;
}
int minStickers(vector<string>& stickers, string target) {
aim = target;
st = stickers;
pre();
for(int i=0;i<target.size();i++) x += 1<<i;
int ans = dfs(x);
if(ans == 1e9) return -1;
return ans;
}
};
按照这种思路同样可以用 bfs 来做,对于当前串能够通过选择一个操作串得到一个新串,操作次数为1,最终首次得到目标串的操作次数便是最小操作次数。
同样,可以转化为状压DP的做法。
遍历所有集合,对于当前集合来说,选择一种字符串删除若干元素来得到一个新的集合,用新集合状态 + 1 得到当前集合状态。
class Solution {
public:
int cnt[60][30];
int tcnt[30];
int f[1<<15];
int minStickers(vector<string>& stickers, string target) {
for(int i=0;i<stickers.size();i++)
{
string s = stickers[i];
for(char c : s)
cnt[i][c - 'a'] ++;
}
int n = target.size();
for(int i=0;i<1<<n;i++) f[i] = 1e9;
f[0] = 0;
for(int i=0;i<1<<n;i++)
{
int x = i;
for(int j=0;j<stickers.size();j++)
{
int tx = x;
for(int k=0;k<26;k++) tcnt[k] = cnt[j][k];
for(int k=0;k<n;k++)
{
if(!(x >> k & 1)) continue;
if(tcnt[target[k] - 'a']) tcnt[target[k] - 'a']--, tx -= 1<<k;
}
f[x] = min(f[x], f[tx] + 1);
}
}
if(f[(1<<n) - 1] == 1e9) return -1;
return f[(1<<n) - 1];
}
};
边栏推荐
- 越来越火的图数据库到底能做什么?
- Electronics manufacturing enterprise deployment WMS what are the benefits of warehouse management system
- 【超详细教程】LVS+KeepAlived高可用部署实战应用
- Tanabata festival coming, VR panoramic look god assists for you
- 优秀的测试/开发程序员,是怎样修炼的?步步为营地去执行......
- 《The Google File System》新说
- Demand analysis of MES management system in electronic assembly industry
- Nanoprobes Mono- Sulfo -NHS-Nanogold的使用和应用
- TypeScript学习
- 114. 如何通过单步调试的方式找到引起 Fiori Launchpad 路由错误的原因
猜你喜欢
随机推荐
建木DevOps流程的快速运用
Linux安装mysql最简单教程(一次成功)
vxe-table 从页面批量删除数据 (不动数据库里的数据)
GraphQL背后处理及执行过程是什么
typescript55-泛型约束
.NET Static Code Weaving - Rougamo Release 1.1.0
The problem of disorganized data output by mnn model
600MHz频段来了,它会是新的黄金频段吗?
C 学生管理系统 显示链表信息、删除链表
Sqlnet. Ora file with the connection of authentication test
ES6高级-迭代器与生成器的用法
114. How to find the cause of Fiori Launchpad routing error by single-step debugging
快速入门EasyX图形编程
Using matlab to solve the linear optimization problem based on matlab dynamic model of learning notes _11 】 【
【超详细】手把手教你搭建MongoDB集群搭建
jmeter distributed stress test
《Greenplum构建实时数据仓库实践》简介
Google Earth Engine ——利用公开的河流数据计算河流的有效宽度
Nanoprobes Alexa Fluor 488 FluoroNanogold 偶联物
取模运算(MOD)