leetCode面試題8.08:從重複符字元的排列組合(回溯去重使用map)
阿新 • • 發佈:2021-01-05
技術標籤:刷題筆記
目錄
一、題目描述
有重複字串的排列組合。編寫一種方法,計算某字串的所有排列組合。
示例1:
輸入:S = "qqe"
輸出:["eqq","qeq","qqe"]
示例2:
輸入:S = "ab"
輸出:["ab", "ba"]
提示:
- 字元都是英文字母。
- 字串長度在[1, 9]之間。
二、解題思路
暴力回溯依然可以解,時間代價較高。依然是看見了好的去重方式,所以記錄下來。
使用map統計字元的出現次數,然後根據次數
這樣操作可以去重的原因在於在map裡統計的只是字元的出現次數,並沒有位置順序的概念,所以自然無論有多少個重負的字元,只計算了一種結果;
例如:兩個a,一個b,一個c;那麼map裡的資料就是{{a,2},{b,1},{c,1}};在根據出現次數回溯過程中,aabc當中的前兩個a跟位置沒有關係,只與次數有關;如果與位置有關就會有和的區別。
三、程式碼實現
#include <bits/stdc++.h> using namespace std; //法一;暴力回溯 unordered_set<string> tmp; void permutation(string str, vector<bool>& used, string S) { if (str.size() == S.size()) { tmp.insert(str); return; } for (int i = 0; i < S.size(); i++) { if (used[i] == false) { used[i] = true; str += S[i]; permutation(str, used, S); used[i] = false; str.pop_back(); } } } vector<string> permutation(string S) { int length = S.size(); vector<bool> used(length, false); string str = ""; permutation(str, used, S); return vector<string>(tmp.begin(), tmp.end()); } //法二:這種方式不好理解(來自力扣題解區) vector<string>res; void process(string S, string& s, int n, vector<int>&flag) { //終止條件 if (s.size() == S.size()) { res.push_back(s); } else { for (int i = 0; i < n; i++) { if (flag[i] == 0) { //剪枝操作 if (i > 0 && S[i] == S[i - 1] && flag[i - 1] == 1)continue;//若有重複字元,跳過該組合 s += S[i]; flag[i] = 1; process(S, s, n, flag); s.pop_back();//回溯到上一步 flag[i] = 0; } } } } vector<string> permutation(string S) { string s; int n = S.size(); sort(S.begin(), S.end());//排序使得重複字元相鄰 vector<int>flag(n); process(S, s, n, flag); return res; } //法三:使用map統計計數(來自力扣題解區) // 執行用時:4 ms, 在所有 C++ 提交中擊敗了94.51%的使用者 // 記憶體消耗:7.2 MB, 在所有 C++ 提交中擊敗了100.00%的使用者 // 使用map去重 vector<string> permutation(string S) { unordered_map<char, int> m; for (auto c : S) { if (m.count(c)) { m[c]++; } else { m[c] = 1; } } vector<string> permutations; backtrack(permutations, m, "", S.size()); return permutations; } void backtrack(vector<string> &permutations, unordered_map<char, int> &m, string prefix, const int len) { if (prefix.size() == len) { permutations.push_back(prefix); return; } //根據次數來回溯 for (unordered_map<char, int>::iterator it = m.begin(); it != m.end(); it++) { if (it->second) { //cout << it->first << " " << it->second << " " << prefix << endl; (it->second)--; // 選擇 backtrack(permutations, m, prefix + it->first, len); // 遞迴判定 (it->second)++; // 回溯 } } } int main() { string S = "qqe"; vector<string> res = permutation(S); for (auto x : res) { cout << x << " "; } return 0; }