当前位置:网站首页>贴纸拼词 —— 记忆化搜索 / 状压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];
}
};
边栏推荐
- LeetCode第三题(Longest Substring Without Repeating Characters)三部曲之三:两次优化
- 114. 如何通过单步调试的方式找到引起 Fiori Launchpad 路由错误的原因
- 研究生新生培训第四周:MobileNetV1, V2, V3
- BioVendor人Clara细胞蛋白(CC16)Elisa试剂盒检测步骤
- 谁说程序员不懂浪漫,表白代码来啦~
- typescript48-函数之间的类型兼容性
- 中原银行实时风控体系建设实践
- Nanoprobes Mono- Sulfo -NHS-Nanogold的使用和应用
- 取模运算(MOD)
- 虚拟机CentOS7中无图形界面安装Oracle
猜你喜欢
2015年开源大事件汇总
redis中常见的问题(缓存穿透,缓存雪崩,缓存击穿,redis淘汰策略)
600MHz频段来了,它会是新的黄金频段吗?
114. How to find the cause of Fiori Launchpad routing error by single-step debugging
虚拟机CentOS7中无图形界面安装Oracle
2022-08-03: What does the following go code output?A: 2; B: 3; C: 1; D: 0.package main import "fmt" func main() { slice := []i
【性能优化】MySQL常用慢查询分析工具
【详细教程】一文参透MongoDB聚合查询
手撕Nacos源码,今日撕服务端源码
特征值与特征向量
随机推荐
typescript58 - generic classes
研究生新生培训第四周:MobileNetV1, V2, V3
iframe通信
Vant3 - click on the corresponding name name to jump to the next page corresponding to the location of the name of the TAB bar
分子个数 数论(欧拉函数 前缀和
2022-08-03: What does the following go code output?A: 2; B: 3; C: 1; D: 0.package main import "fmt" func main() { slice := []i
【虚拟户生态平台】虚拟化平台安装时遇到的坑
Demand analysis of MES management system in electronic assembly industry
2023年航空航天、机械与机电工程国际会议(CAMME 2023)
Mvc, Mvp and Mvvm
2015年开源大事件汇总
typescript48-函数之间的类型兼容性
typescript56 - generic interface
小米--测试开发
OpenCV如何实现Sobel边缘检测
A Preliminary Study of RSS Subscription to WeChat Official Account-feed43
typescript54 - generic constraints
Nanoprobes 棕榈酰纳米金相关说明书
outputBufferIndex = mDecode.dequeueOutputBuffer(bufferInfo, 0) 一直返回为-1
新一代服务网关Gateway的实践笔记