假設區間都是不相交的區間,此時區間彼此是獨立的,因此只需要兩兩交換看交換後字典序是否會變大,此時是典序的貪心思路。如果出現區間相交的情況,由於可以進行任意多次交換,那麼這組區域的字典序最小就是將他們排序。
因此思路是隻需要找到所有聯通區間,然後將其中對應字母排序,然後將排序後的結果插入到原來的字符串中,既可以得到重新組合後新生成的字符串。
統計區間的聯通性,使用到的數據結構是並查集。並查集處理完後,用一個HashMap數據結構來保存,每個根節點對應的字符串映射,我們遍歷一遍字符串,將這個字符映射建立起來。然後我們遍歷整個hashmap,對字符串排序,我們按照從大到小排序。這樣在遍歷一次字符串索引,找到其對應的根,在通過HashMap找到對應的字符串數組,然後取出最後一個,即爲這個位置要放的字符,最後就可以完成。
class DisjointSetUnion {
private:
vector<int> p;
int n;
public:
DisjointSetUnion(int _n) {
n = _n;
p.resize(n);
for (int i = 0; i < n; i++) {
p[i] = i;
}
}
int find(int x) {
if(p[x]!=x) p[x] = find(p[x]);
return p[x];
}
void unionSet(int x, int y) {
p[find(x)] = find(y);
}
};
class Solution {
public:
string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
DisjointSetUnion dsu(s.length());
for (auto& it : pairs) {
dsu.unionSet(it[0], it[1]);
}
unordered_map<int, vector<int>> mp;
for (int i = 0; i < s.length(); i++) {
mp[dsu.find(i)].emplace_back(s[i]);
}
for (auto& [x, vec] : mp) {
sort(vec.begin(), vec.end(), greater<int>());
}
for (int i = 0; i < s.length(); i++) {
int x = dsu.find(i);
s[i] = mp[x].back();
mp[x].pop_back();
}
return s;
}
};