classSolution { public: intminStickers(vector<string>& stickers, string target){ int n = stickers.size(); vector<vector<int>> m(n, vector<int>(26)); for (int i = 0; i < n; ++i) { for (char c : stickers[i]) { ++m[i][c - 'a']; } } int res = dfs(m, target); return res == INT_MAX ? -1 : res; }
longdfs(constvector<vector<int>> &m, conststring &target){ if (target.empty()) return0; if (cache.count(target)) return cache[target]; vector<int> mt(26); for (char c : target) { ++mt[c - 'a']; } int n = m.size(); long res = INT_MAX; // 把当前结果初始化为INT_MAX for (int i = 0; i < n; ++i) { // if (m[i][target[0] - 'a'] == 0) continue; // 这个优化剪枝很神奇,可以避免潜在的对target完全没有贡献的sticker,暂时无法贡献的sticker等到其他sticker把部分target拼凑出来以后再贡献 string s; for (int j = 0; j < 26; ++j) { if (mt[j] > m[i][j]) { // 这里大于或者大于等于无异,因为是要去掉当前sticker中可以拼成target的字母,所以如果sticker中的某个对应字母比target中的多,那么新组成的target就不需要添加该字母,所以只需要考虑sticker中对应字母不够拼成target的情况 s.append(mt[j] - m[i][j], 'a' + j); } } if (s == target) continue; // 如果没有之前那个优化,一定要判断新target和原target是否一样,避免重复递归 res = min(res, dfs(m, s) + 1); } return cache[target] = res; }