返回
用贴纸拼凑单词:巧解 C/C++ 难题 691
后端
2023-12-09 18:08:16
问题背景
假设我们拥有若干种贴纸,每种贴纸上都印有一个小写英语单词。现在,我们需要使用这些贴纸拼凑出一个特定的目标单词 tar
。问题是,我们如何才能高效地完成这一任务?
递归解决方案
最直接的想法是采用递归算法。我们可以逐个尝试每个贴纸,检查它是否能与目标单词 tar
中的某个前缀匹配。如果匹配,我们就可以递归地继续尝试拼凑剩余部分。
bool canForm(string tar, vector<string>& stickers) {
if (tar.empty()) return true;
for (string& sticker : stickers) {
for (int i = 0; i < tar.size(); i++) {
if (sticker.find(tar[i]) != string::npos) {
if (canForm(tar.substr(i + 1), stickers)) return true;
}
}
}
return false;
}
然而,这种递归解决方案存在效率问题,因为当贴纸数量较多或目标单词较长时,它会陷入大量的重复计算。
动态规划解决方案
为了优化效率,我们可以采用动态规划算法。动态规划将问题分解成子问题,并存储中间结果以避免重复计算。对于本题,我们可以定义状态 dp[i]
,表示目标单词 tar
的前 i
个字符是否可以用贴纸拼凑出来。
bool canForm(string tar, vector<string>& stickers) {
vector<bool> dp(tar.size() + 1, false);
dp[0] = true;
for (int i = 1; i <= tar.size(); i++) {
for (string& sticker : stickers) {
for (int j = i; j >= 0; j--) {
if (dp[j] && tar.substr(j, i - j).find(sticker) != string::npos) {
dp[i] = true;
break;
}
}
}
}
return dp[tar.size()];
}
在动态规划算法中,我们按顺序检查目标单词的每个前缀,并尝试使用贴纸拼凑它。如果一个前缀可以用贴纸拼凑出来,我们就把它标记为 true
,并继续检查下一个前缀。通过这种方式,我们避免了重复计算,并大大提高了算法的效率。
总结
C++ 中的 691. 贴纸拼词难题需要我们运用巧妙的算法来解决。递归算法虽然简单直观,但效率较低。动态规划算法则通过分解问题并存储中间结果,有效地避免了重复计算,从而提供了高效的解决方案。通过学习这一难题的求解过程,我们可以提升自己的 C++ 编程技能,在字符串处理和算法设计方面取得进步。