1. DFS Connected Components Traversal
Intuition
Build an undirected graph where edges are the swap pairs. Maintain a visited array. For each unvisited index i, perform DFS to collect all indices in its connected component. Extract the characters at these indices, sort the indices and characters, and assign the sorted characters into the sorted indices.
When to apply: Basic graph search approach without DSU.
Algorithm
- Build adjacency list
adjfrompairs. - Initialize
visitedarray of sizenwith false. - For
ifrom 0 ton - 1: - If
!visited[i]: - Run DFS collecting all connected
indices. - Extract
chars = [s[idx] for idx in indices]. - Sort
indicesand sortchars. - Assign
res[indices[k]] = chars[k]. - Return
res.
DFS Connected Components Traversal
2 of 2 questions left todayObservation: Swapping is transitive: if $a$ swaps with $b$ and $b$ with $c$, any permutation of ${a, b, c}$ can be achieved
Observation: Swapping is transitive: if a swaps with b and b with c, any permutation of {a, b, c} can be achieved.
Decision: Model indices as an undirected graph. Find connected components using DFS.
Invariant: All indices within a connected component can freely reorder their characters.
#include <iostream>#include <string>#include <vector>#include <algorithm> class Solution { void dfs(int u, const std::vector<std::vector<int>>& adj, std::vector<bool>& visited, std::vector<int>& indices, std::string& chars, const std::string& s) { visited[u] = true; indices.push_back(u); chars.push_back(s[u]); for (int v : adj[u]) { if (!visited[v]) { dfs(v, adj, visited, indices, chars, s); } } }public: std::string smallestStringWithSwaps(std::string s, std::vector<std::vector<int>>& pairs) { int n = s.size(); std::vector<std::vector<int>> adj(n); for (const auto& p : pairs) { adj[p[0]].push_back(p[1]); adj[p[1]].push_back(p[0]); } std::vector<bool> visited(n, false); std::string res = s; for (int i = 0; i < n; ++i) { if (!visited[i]) { std::vector<int> indices; std::string chars = ""; dfs(i, adj, visited, indices, chars, s); std::sort(indices.begin(), indices.end()); std::sort(chars.begin(), chars.end()); for (size_t k = 0; k < indices.size(); ++k) { res[indices[k]] = chars[k]; } } } return res; }}; int main() { Solution sol; std::vector<std::vector<int>> pairs = {{0,3},{1,2}}; std::cout << sol.smallestStringWithSwaps("dcab", pairs) << std::endl; // "bacd" return 0;}Time & Space Complexity
- Time complexity:
O(V + E + V log V)— Graph traversal visits all V vertices and E edges once; sorting component characters takes O(V log V). - Space complexity:
O(V + E) for adjacency list
Why Brute Force Doesn't Scale:
Using counting sort with 26 buckets sorts each component in linear O(K) time.
Disjoint Set Union uses compact 1D integer arrays.