1202. 交换字符串中的元素
时间:2021年1月11日
知识点:图、并查集
题目链接
题目
给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。
你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。
示例 1:
输入:s = “dcab”, pairs = [[0,3],[1,2]]
输出:“bacd”
解释:
交换 s[0] 和 s[3], s = “bcad”
交换 s[1] 和 s[2], s = “bacd”
示例 2:
输入:s = “dcab”, pairs = [[0,3],[1,2],[0,2]]
输出:“abcd”
解释:
交换 s[0] 和 s[3], s = “bcad”
交换 s[0] 和 s[2], s = “acbd”
交换 s[1] 和 s[2], s = “abcd”
示例 3:
输入:s = “cba”, pairs = [[0,1],[1,2]]
输出:“abc”
解释:
交换 s[0] 和 s[1], s = “bca”
交换 s[1] 和 s[2], s = “bac”
交换 s[0] 和 s[1], s = “abc”
提示:
- 1 <= s.length <= 10^5
- 0 <= pairs.length <= 10^5
- 0 <= pairs[i][0], pairs[i][1] < s.length
- s 中只含有小写英文字母
解法:
- 这是一道并查集的题
- 通过对pairs的分析 把他想象成边 每个字符看作节点 我们可以知道如果哪些字符是连通的
- 如果几个字符是连通的 那么他们可以随意交换位置 可以得出最小的字符
- 对于多个连通 以祖先节点为key 所有连通的成为vector 每个排好序
- 然后放入答案数组 这里是重点 可能不太好想 用并查集的find找到对应的连通 返回一个字符即可
代码
//头文件
#include "cheader.h"
class Solution {
public:
struct UN{
vector<int> ancestor;
UN(int x){
ancestor.resize(x);
for(int i = 0;i < x;i++)
ancestor[i] = i;
}
int find(int x){
if(ancestor[x] == x)
return x;
else
return ancestor[x] = find(ancestor[x]);
}
void merge(int a, int b){
ancestor[find(a)] = find(b);
}
};
string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
int n = s.size();
UN un = UN(n);
for(vector<int> x: pairs){
un.merge(x[0], x[1]);
}
unordered_map<int, vector<char>> mp;
// 在同一个连通图中的放在一起
for(int i = 0; i < n; i++)
mp[un.find(i)].push_back(s[i]);
//遍历每个连通 同一个连通中的字符 从大到小排序
for(auto& [x,ch]: mp)
sort(ch.begin(),ch.end(),greater<char>());
string ans;
// 找到每个字符(这里用下标建立的并查集)所对应的连通 取出连通中最小的字符
for(int i = 0; i < n; i++){
int x = un.find(i);
ans += mp[x].back();
mp[x].pop_back();
}
return ans;
}
};
int main()
{
Solution S;
string s = "dcab";
vector<vector<int>> pairs;
pairs.push_back(vector<int> {0,3});
pairs.push_back(vector<int> {1,2});
pairs.push_back(vector<int> {0,2});
cout<<S.smallestStringWithSwaps(s, pairs);
return 0;
}
今天也是爱zz的一天哦!