当前位置:网站首页>贴纸拼词 —— 记忆化搜索 / 状压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];
}
};
边栏推荐
猜你喜欢
c语言分层理解(c语言指针(上))
GeoAO:一种快速的环境光遮蔽方案
【面经】被虐了之后,我翻烂了equals源码,总结如下
GraphQL背后处理及执行过程是什么
MPLS Comprehensive Experiment
《Greenplum构建实时数据仓库实践》简介
Demand analysis of MES management system in electronic assembly industry
Shell编程之循环语句(for、while)
The 600MHz band is here, will it be the new golden band?
2022年8月份DAMA-CDGA/CDGP数据治理认证招生简章
随机推荐
win10+cuda11.7+pytorch1.12.0 installation
Jmeter cross-platform operation CSV files
DataBinding下的RecycleView适配器Adapter基类
jmeter跨平台运行csv等文件
c语言分层理解(c语言指针(上))
OpenCV如何实现Sobel边缘检测
C 学生管理系统 显示链表信息、删除链表
七夕活动浪漫上线,别让网络拖慢和小姐姐的开黑时间
Electronics manufacturing enterprise deployment WMS what are the benefits of warehouse management system
LeetCode third topic (the Longest Substring Without Repeating Characters) trilogy # 3: two optimization
A Preliminary Study of RSS Subscription to WeChat Official Account-feed43
手撕Gateway源码,今日撕工作流程、负载均衡源码
小米--测试开发
ENS域名注册量创历史新高 逆市增长之势?光环之下存在炒作风险
"Miscellaneous" barcode by Excel as a string
求解同余方程 数论 扩展欧几里得
The 600MHz band is here, will it be the new golden band?
带你造轮子,自定义一个随意拖拽可吸边的悬浮View组件
BioVendor人Clara细胞蛋白(CC16)Elisa试剂盒检测步骤
jmeter distributed stress test