LeetCode 1202. 交换字符串中的元素【无向图连通分量】中等

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。

你可以 任意多次交换pairs 中任意一对索引处的字符。

返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。

示例 1:

java 复制代码
输入:s = "dcab", pairs = [[0,3],[1,2]]
输出:"bacd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[1] 和 s[2], s = "bacd"

示例 2:

java 复制代码
输入: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:

java 复制代码
输入: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 中只含有小写英文字母

方法 建图+DFS

在每对 p a i r pair pair 中的索引 a a a 和 b b b 之间连边,得到一个无向图 G G G 。 G G G 的同一个连通块中的节点(下标)可以随意交换。求连通块可用BFS、DFS和并查集(在线查询时更优)。

将每个连通块中的下标对应的字符形成的序列,从小到大排序。从而整体得到的字符串的字典序最小。

java 复制代码
class Solution {
    private void dfs(List<Integer>[] g, int i, boolean[] vis, List<Integer> comps) {
        vis[i] = true;
        comps.add(i);
        for (int j : g[i]) {
            if (vis[j]) continue;
            dfs(g, j, vis, comps);
        }
    }
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        int n = s.length();
        List<Integer>[] graph = new ArrayList[n];
        Arrays.setAll(graph, _ -> new ArrayList<>());
        for (List<Integer> pair: pairs) {
            int i = pair.get(0);
            int j = pair.get(1);
            graph[i].add(j);
            graph[j].add(i);
        }
        char[] str = s.toCharArray();
        boolean[] vis = new boolean[n];
        for (int i = 0; i < n; ++i) {
            if (vis[i]) continue;
            List<Integer> comps = new ArrayList<>(); // 连通分量的下标
            dfs(graph, i, vis, comps);
            Collections.sort(comps);
            char[] tc = new char[comps.size()];
            for (int j = 0; j < comps.size(); ++j) {
                tc[j] = str[comps.get(j)];
            }
            Arrays.sort(tc);
            for (int j = 0; j < tc.length; ++j) {
                str[comps.get(j)] = tc[j];
            }
        }
        return String.valueOf(str);
    }
}

复杂度分析:

  • 时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn) , n n n 为 s s s 的长度。
  • 空间复杂度: O ( n ) O(n) O(n) 。
相关推荐
Sagittarius_A*1 小时前
后量子密码|通识认知 03|量子威胁辟谣:Grover 算法对对称密码的影响与误区
算法·信息安全·密码学·量子计算·pqc·后量子密码
测试者家园2 小时前
AI如何发现测试人员看不到的问题?
人工智能·职场和发展·agent·智能化测试·幻觉检测·行为漂移
QAQo7T3 小时前
Python组蓝桥杯备赛超详细知识点总结笔记_排序算法篇
笔记·python·算法·蓝桥杯·排序算法
普通网友3 小时前
蓝桥杯 DP 优化:从 O (n²) 到 O (n) 的滚动数组实战
职场和发展·蓝桥杯
醉颜凉3 小时前
蓝桥杯2025年第十六届省赛真题-好串的数目
职场和发展·蓝桥杯
醉颜凉3 小时前
蓝桥杯2025年第十六届省赛真题-最大数字 Python题解
python·职场和发展·蓝桥杯
千里之行,始于足下sanhai3 小时前
P8686 [蓝桥杯 2019 省 A] 修改数组 - 数字魔法大冒险 题解
c++·算法·动态规划
2301_806204463 小时前
蓝桥杯第十四届省赛代码参考
职场和发展·蓝桥杯
Ronin-Lotus3 小时前
蓝桥杯篇---EEPROM内部存储地址
职场和发展·蓝桥杯·c·eeprom·keil
小星星闪亮登场3 小时前
Codeforces Round 1115 ( Div. 2)
数据结构·c++·算法·贪心算法·排序算法·codeforces