57
57
58
58
<!-- 这里可写通用的实现逻辑 -->
59
59
60
- 并查集。对于本题,索引对具备传递性。即如果索引对是 ` [0,2] ` , ` [0, 3] ` ,那么索引 0、2、3 可以进行任意交换。我们可以利用并查集,遍历每个索引对,将其中的两个索引进行合并,得到并查集,连在一起的索引对应的字符按照字典序排列,这里可以利用优先级队列实现(也可以先用列表存储,再排序)。
60
+ ** 方法一: 并查集**
61
61
62
- 最后遍历字符串,找到每个字符的根元素,并替换为字典序中对应的字符 。
62
+ 我们注意到,索引对具有传递性,即如果 $a$ 与 $b$ 可交换,而 $b$ 与 $c$ 可交换,那么 $a$ 与 $c$ 也可交换。因此,我们可以考虑使用并查集维护这些索引对的连通性,将属于同一个连通分量的字符按照字典序排序 。
63
63
64
- 以下是并查集的几个常用模板 。
64
+ 最后,遍历字符串,对于当前位置的字符,我们将其替换为该连通分量中最小的字符,然后从该连通分量中取出该字符,继续遍历字符串即可 。
65
65
66
- 模板 1——朴素并查集:
67
-
68
- ``` python
69
- # 初始化,p存储每个点的父节点
70
- p = list (range (n))
71
-
72
- # 返回x的祖宗节点
73
- def find (x ):
74
- if p[x] != x:
75
- # 路径压缩
76
- p[x] = find(p[x])
77
- return p[x]
78
-
79
-
80
- # 合并a和b所在的两个集合
81
- p[find(a)] = find(b)
82
- ```
83
-
84
- 模板 2——维护 size 的并查集:
85
-
86
- ``` python
87
- # 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
88
- p = list (range (n))
89
- size = [1 ] * n
90
-
91
- # 返回x的祖宗节点
92
- def find (x ):
93
- if p[x] != x:
94
- # 路径压缩
95
- p[x] = find(p[x])
96
- return p[x]
97
-
98
- # 合并a和b所在的两个集合
99
- if find(a) != find(b):
100
- size[find(b)] += size[find(a)]
101
- p[find(a)] = find(b)
102
- ```
103
-
104
- 模板 3——维护到祖宗节点距离的并查集:
105
-
106
- ``` python
107
- # 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离
108
- p = list (range (n))
109
- d = [0 ] * n
110
-
111
- # 返回x的祖宗节点
112
- def find (x ):
113
- if p[x] != x:
114
- t = find(p[x])
115
- d[x] += d[p[x]]
116
- p[x] = t
117
- return p[x]
118
-
119
- # 合并a和b所在的两个集合
120
- p[find(a)] = find(b)
121
- d[find(a)] = distance
122
- ```
66
+ 时间复杂度 $O(n \times \log n + m \times \alpha(m))$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别为字符串的长度和索引对的数量,而 $\alpha$ 为阿克曼函数的反函数。
123
67
124
68
<!-- tabs:start -->
125
69
@@ -130,7 +74,7 @@ d[find(a)] = distance
130
74
``` python
131
75
class Solution :
132
76
def smallestStringWithSwaps (self , s : str , pairs : List[List[int ]]) -> str :
133
- def find (x ) :
77
+ def find (x : int ) -> int :
134
78
if p[x] != x:
135
79
p[x] = find(p[x])
136
80
return p[x]
@@ -139,10 +83,12 @@ class Solution:
139
83
p = list (range (n))
140
84
for a, b in pairs:
141
85
p[find(a)] = find(b)
142
- mp = defaultdict(list )
86
+ d = defaultdict(list )
143
87
for i, c in enumerate (s):
144
- heappush(mp[find(i)], c)
145
- return ' ' .join(heappop(mp[find(i)]) for i in range (n))
88
+ d[find(i)].append(c)
89
+ for i in d.keys():
90
+ d[i].sort(reverse = True )
91
+ return " " .join(d[find(i)].pop() for i in range (n))
146
92
```
147
93
148
94
### ** Java**
@@ -156,21 +102,27 @@ class Solution {
156
102
public String smallestStringWithSwaps (String s , List<List<Integer > > pairs ) {
157
103
int n = s. length();
158
104
p = new int [n];
105
+ List<Character > [] d = new List [n];
159
106
for (int i = 0 ; i < n; ++ i) {
160
107
p[i] = i;
108
+ d[i] = new ArrayList<> ();
161
109
}
162
- for (List<Integer > pair : pairs) {
163
- p[find(pair. get(0 ))] = find(pair. get(1 ));
110
+ for (var pair : pairs) {
111
+ int a = pair. get(0 ), b = pair. get(1 );
112
+ p[find(a)] = find(b);
164
113
}
165
- Map<Integer , PriorityQueue<Character > > mp = new HashMap<> ();
166
- char [] chars = s. toCharArray();
114
+ char [] cs = s. toCharArray();
167
115
for (int i = 0 ; i < n; ++ i) {
168
- mp. computeIfAbsent(find(i), k - > new PriorityQueue<> ()). offer(chars[i]);
116
+ d[find(i)]. add(cs[i]);
117
+ }
118
+ for (var e : d) {
119
+ e. sort((a, b) - > b - a);
169
120
}
170
121
for (int i = 0 ; i < n; ++ i) {
171
- chars[i] = mp. get(find(i)). poll();
122
+ var e = d[find(i)];
123
+ cs[i] = e. remove(e. size() - 1 );
172
124
}
173
- return new String (chars );
125
+ return String . valueOf(cs );
174
126
}
175
127
176
128
private int find (int x ) {
@@ -187,27 +139,33 @@ class Solution {
187
139
``` cpp
188
140
class Solution {
189
141
public:
190
- vector<int > p;
191
-
192
142
string smallestStringWithSwaps(string s, vector<vector<int >>& pairs) {
193
- int n = s.length();
194
- p.resize(n);
195
- for (int i = 0; i < n; ++i) p[i] = i;
196
- for (auto& pair : pairs) p[find(pair[0])] = find(pair[1]);
197
- unordered_map<int, vector<char>> mp;
198
- for (int i = 0; i < n; ++i) mp[find(i)].push_back(s[i]);
199
- for (auto& [k, v] : mp) sort(v.rbegin(), v.rend());
200
- string ans;
143
+ int n = s.size();
144
+ int p[ n] ;
145
+ iota(p, p + n, 0);
146
+ vector<char > d[ n] ;
147
+ function<int(int)> find = [ &] (int x) -> int {
148
+ if (p[ x] != x) {
149
+ p[ x] = find(p[ x] );
150
+ }
151
+ return p[ x] ;
152
+ };
153
+ for (auto e : pairs) {
154
+ int a = e[ 0] , b = e[ 1] ;
155
+ p[ find(a)] = find(b);
156
+ }
201
157
for (int i = 0; i < n; ++i) {
202
- ans.push_back(mp[find(i)].back());
203
- mp[find(i)].pop_back();
158
+ d[ find(i)] .push_back(s[ i] );
204
159
}
205
- return ans;
206
- }
207
-
208
- int find (int x) {
209
- if (p[ x] != x) p[ x] = find(p[ x] );
210
- return p[ x] ;
160
+ for (auto& e : d) {
161
+ sort(e.rbegin(), e.rend());
162
+ }
163
+ for (int i = 0; i < n; ++i) {
164
+ auto& e = d[ find(i)] ;
165
+ s[ i] = e.back();
166
+ e.pop_back();
167
+ }
168
+ return s;
211
169
}
212
170
};
213
171
```
@@ -218,34 +176,65 @@ public:
218
176
func smallestStringWithSwaps(s string, pairs [][]int) string {
219
177
n := len(s)
220
178
p := make([]int, n)
179
+ d := make([][]byte, n)
221
180
for i := range p {
222
181
p[i] = i
223
182
}
224
- var find func(x int) int
183
+ var find func(int) int
225
184
find = func(x int) int {
226
185
if p[x] != x {
227
186
p[x] = find(p[x])
228
187
}
229
188
return p[x]
230
189
}
231
190
for _, pair := range pairs {
232
- p[find(pair[0])] = find(pair[1])
191
+ a, b := pair[0], pair[1]
192
+ p[find(a)] = find(b)
233
193
}
234
- mp := make(map[int][]rune)
235
- for i, c := range s {
236
- mp[find(i)] = append(mp[find(i)], c)
194
+ cs := []byte(s)
195
+ for i, c := range cs {
196
+ j := find(i)
197
+ d[j] = append(d[j], c)
237
198
}
238
- for _, v := range mp {
239
- sort.Slice(v, func(i, j int) bool {
240
- return v[i] < v[j]
241
- })
199
+ for i := range d {
200
+ sort.Slice(d[i], func(a, b int) bool { return d[i][a] > d[i][b] })
242
201
}
243
- var ans []rune
244
- for i := 0; i < n; i++ {
245
- ans = append(ans, mp[find(i)][0])
246
- mp[find(i) ] = mp[find(i)][1: ]
202
+ for i := range cs {
203
+ j := find(i)
204
+ cs[i] = d[j][len(d[j])-1]
205
+ d[j ] = d[j][:len(d[j])-1 ]
247
206
}
248
- return string(ans)
207
+ return string(cs)
208
+ }
209
+ ```
210
+
211
+ ### ** TypeScript**
212
+
213
+ ``` ts
214
+ function smallestStringWithSwaps(s : string , pairs : number [][]): string {
215
+ const n = s .length ;
216
+ const p = new Array (n ).fill (0 ).map ((_ , i ) => i );
217
+ const find = (x : number ): number => {
218
+ if (p [x ] !== x ) {
219
+ p [x ] = find (p [x ]);
220
+ }
221
+ return p [x ];
222
+ };
223
+ const d: string [][] = new Array (n ).fill (0 ).map (() => []);
224
+ for (const [a, b] of pairs ) {
225
+ p [find (a )] = find (b );
226
+ }
227
+ for (let i = 0 ; i < n ; ++ i ) {
228
+ d [find (i )].push (s [i ]);
229
+ }
230
+ for (const e of d ) {
231
+ e .sort ((a , b ) => b .charCodeAt (0 ) - a .charCodeAt (0 ));
232
+ }
233
+ const ans: string [] = [];
234
+ for (let i = 0 ; i < n ; ++ i ) {
235
+ ans .push (d [find (i )].pop ()! );
236
+ }
237
+ return ans .join (' ' );
249
238
}
250
239
```
251
240
0 commit comments