難度困難40收藏分享切換爲英文關注反饋
我們給出了 N 種不同類型的貼紙。每個貼紙上都有一個小寫的英文單詞。
你希望從自己的貼紙集合中裁剪單個字母並重新排列它們,從而拼寫出給定的目標字符串 target
。
如果你願意的話,你可以不止一次地使用每一張貼紙,而且每一張貼紙的數量都是無限的。
拼出目標 target
所需的最小貼紙數量是多少?如果任務不可能,則返回 -1。
示例 1:
輸入:
["with", "example", "science"], "thehat"
輸出:
3
解釋:
我們可以使用 2 個 "with" 貼紙,和 1 個 "example" 貼紙。 把貼紙上的字母剪下來並重新排列後,就可以形成目標 “thehat“ 了。 此外,這是形成目標字符串所需的最小貼紙數量。
示例 2:
輸入:
["notice", "possible"], "basicbasic"
輸出:
-1
解釋:
我們不能通過剪切給定貼紙的字母來形成目標“basicbasic”。
提示:
stickers
長度範圍是[1, 50]
。stickers
由小寫英文單詞組成(不帶撇號)。target
的長度在[1, 15]
範圍內,由小寫字母組成。- 在所有的測試案例中,所有的單詞都是從 1000 個最常見的美國英語單詞中隨機選取的,目標是兩個隨機單詞的串聯。
- 時間限制可能比平時更具挑戰性。預計 50 個貼紙的測試案例平均可在35ms內解決。
題目分析:
1. 記憶化搜索。 代碼中的一個比較關鍵的優化點就是會把沒有當前target第一個字符的sticker去掉,這樣可以減少每個狀態所需要計算的sticker數目。
class Solution {
public:
int minStickers(vector<string>& stickers, string target) {
int stickerSize = stickers.size();
vector<vector<int>> V(stickerSize, vector<int>(26,0));
for(int i = 0; i < stickerSize; i++){
for(int j = 0; j < stickers[i].size(); j++){
V[i][stickers[i][j] - 'a'] += 1;
}
}
unordered_map<string, int> M; M[""] = 0;
int ans = DFS(V, M, target);
if(ans > 20) return - 1;
return ans;
}
int DFS(vector<vector<int>> &V, unordered_map<string, int>& M, string target){
if(M.find(target) != M.end()){
return M[target];
}
int res = 9999;
vector<int> tt(26,0);
for(auto x: target){tt[x-'a'] += 1;}
for(int i = 0; i < V.size(); i++){
if(V[i][target[0] - 'a'] == 0) continue;
else{
string t = "";
for(int j = 0; j < 26; j++){
if(tt[j] > V[i][j]){
t += string(tt[j] - V[i][j], 'a' + j);
}
}
res = min( res, DFS(V, M, t));
}
}
M[target] = res + 1;
return M[target];
}
};