标签:访问 ack string begin 表示 列合并 site highlight int
问题:
给定字符串s,和可进行交换的index对数组。
对字符串s的各个位置index,可根据交换数组所示的两两交换(次数不限),求进行交换后,可得最小的字符串。
Example 1: Input: s = "dcab", pairs = [[0,3],[1,2]] Output: "bacd" Explaination: Swap s[0] and s[3], s = "bcad" Swap s[1] and s[2], s = "bacd" Example 2: Input: s = "dcab", pairs = [[0,3],[1,2],[0,2]] Output: "abcd" Explaination: Swap s[0] and s[3], s = "bcad" Swap s[0] and s[2], s = "acbd" Swap s[1] and s[2], s = "abcd" Example 3: Input: s = "cba", pairs = [[0,1],[1,2]] Output: "abc" Explaination: Swap s[0] and s[1], s = "bca" Swap s[1] and s[2], s = "bac" Swap s[0] and s[1], s = "abc" Constraints: 1 <= s.length <= 10^5 0 <= pairs.length <= 10^5 0 <= pairs[i][0], pairs[i][1] < s.length s only contains lower case English letters.
解法:
本问题为:连通图问题,
对两组可交换的index对,出现重复index的话,那么这两个组之间的3个index都可以任意交换。
那么,题意可转换为:
在给出的可交换对数组中,可形成多个可任意交换的index序列,
这几个序列之间没有交集,但是序列内部可进行随意排序,
求出每个序列的最小排序,并将这些序列合并。
本问题的关键:连通图的构造
方法一:
dfs:深度优先排序:
对图中的每一个未访问过的节点a(一个连通图),轮询:
对每个节点a 的邻接点 adjList,依次轮询标记,标记为一个组。graphid
访问过的节点,要标记 visited
最后,graphid相同的即为一个连通图。
这里,对每一个连通图,要做固定操作的话,可在标记graphid的同时,直接进行操作。
(对于本题,则是记录:当前连通图的节点 idx[] )
(在每一个连通图遍历完毕的时候,对重新取得节点对应的字符,组成新的字符串tmp,对tmp排序,再将新的排序赋值回原字符串s中)
代码参考:
1 class Solution { 2 public: 3 vector<bool> visited; 4 vector<vector<int>> adjList; 5 string tmp; 6 vector<int> idx; 7 8 void dfs(int i, string& s){ 9 visited[i]=true;//marked->0 设置访问 10 tmp.push_back(s[i]); 11 idx.push_back(i);//同一层连通图 12 for(int p:adjList[i]){ 13 if(!visited[p]){//marked==0 未访问过 14 dfs(p, s); 15 } 16 } 17 } 18 string makepinfo(string& s){ 19 string res(s.length(),0); 20 for(int i=0; i<s.length(); i++){ 21 tmp=""; 22 idx.clear(); 23 if(!visited[i]){//未访问过 24 dfs(i, s); 25 sort(tmp.begin(), tmp.end()); 26 sort(idx.begin(), idx.end()); 27 for(int t=0; t<tmp.size(); t++){ 28 res[idx[t]]=tmp[t]; 29 } 30 } 31 } 32 return res; 33 } 34 35 string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) { 36 visited.resize(s.length(),false); 37 adjList.resize(s.length()); 38 for(auto p:pairs){ 39 adjList[p[0]].push_back(p[1]); 40 adjList[p[1]].push_back(p[0]); 41 } 42 return makepinfo(s); 43 } 44 };
方法二:
直接使用
数组vector un表示是否为一个连通图:
un[i]:元素i的邻接元素。
1 UN(int n){//初始化连通组,自己的下一个为自己,每个元素孤立存在 2 un.resize(n); 3 for(int u=0; u<n; u++){ 4 un[u]=u; 5 } 6 }
un.unite(i, j):链接两个元素。
(使用find,寻找两个节点的终点)
(如果终点相同,说明两元素已经在同一个连通图中)
(否则,将 i 的终点 un[fi] 指向 j )
1 void unite(int i, int j){//合并连通组 i和j 2 int fi=find(i); 3 int fj=find(j); 4 if(fi!=fj){//两个连通图的终点不一样,则合并连通图i和j 5 un[fi]=j; 6 }//否则,i和j是连通图 7 }
un.find(i):找到元素i所在连通图的终点节点。
1 int find(int i){ 2 int x=un[i]; 3 if(un[x]!=x){ 4 un[i]=find(x); 5 } 6 return un[i]; 7 }
那么对于本题,首先构造un
对每一对pair,进行unite。
构造完毕后,构造连通图组group
key:连通图终点元素,value:连通图的各个节点。
1 unordered_map<int, vector<int>> group; 2 //使用连通图UN,做成连通图组,key:UN每个连通图的终点,value:连通图的各个节点 3 for(int i=0; i<N; i++){ 4 group[un.find(i)].push_back(i); 5 }
然后遍历每个连通图,进行string tmp排序
并合并各个tmp的动作。
1 //使用group排序每个连通图的string 2 for(auto g:group){ 3 string tmp(""); 4 for(int idx:g.second){ 5 tmp.push_back(s[idx]); 6 } 7 sort(tmp.begin(), tmp.end()); 8 int i=0; 9 for(int idx:g.second){ 10 s[idx]=tmp[i]; 11 i++; 12 } 13 }
总代码参考:
1 class Solution { 2 public: 3 class UN { 4 public: 5 vector<int> un; 6 UN(int n){//初始化连通组,自己的下一个为自己,每个元素孤立存在 7 un.resize(n); 8 for(int u=0; u<n; u++){ 9 un[u]=u; 10 } 11 } 12 int find(int i){ 13 int x=un[i]; 14 if(un[x]!=x){ 15 un[i]=find(x); 16 } 17 return un[i]; 18 } 19 void unite(int i, int j){//合并连通组 i和j 20 int fi=find(i); 21 int fj=find(j); 22 if(fi!=fj){//两个连通图的终点不一样,则合并连通图i和j 23 un[fi]=j; 24 }//否则,i和j是连通图 25 } 26 }; 27 28 string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) { 29 int N=s.length(); 30 UN un(N); 31 for(auto p:pairs){//使用pairs,做成连通图UN 32 un.unite(p[0], p[1]); 33 } 34 unordered_map<int, vector<int>> group; 35 //使用连通图UN,做成连通图组,key:UN每个连通图的终点,value:连通图的各个节点 36 for(int i=0; i<N; i++){ 37 group[un.find(i)].push_back(i); 38 } 39 //使用group排序每个连通图的string 40 for(auto g:group){ 41 string tmp(""); 42 for(int idx:g.second){ 43 tmp.push_back(s[idx]); 44 } 45 sort(tmp.begin(), tmp.end()); 46 int i=0; 47 for(int idx:g.second){ 48 s[idx]=tmp[i]; 49 i++; 50 } 51 } 52 return s; 53 } 54 };
1202. Smallest String With Swaps
标签:访问 ack string begin 表示 列合并 site highlight int
原文地址:https://www.cnblogs.com/habibah-chang/p/13168838.html