返回

用贴纸拼凑单词:巧解 C/C++ 难题 691

后端

问题背景

假设我们拥有若干种贴纸,每种贴纸上都印有一个小写英语单词。现在,我们需要使用这些贴纸拼凑出一个特定的目标单词 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++ 编程技能,在字符串处理和算法设计方面取得进步。