【数据结构-并查集】力扣1202. 交换字符串中的元素

news/2025/2/21 11:04:10/

给你一个字符串 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 中只含有小写英文字母

并查集

class UnionFind{
private:vector<int> parent;
public:UnionFind(int n){parent.resize(n);for(int i = 0; i < n; i++){parent[i] = i;}}void unite(int index1, int index2){parent[find(index2)] = find(index1);}int find(int index){if(parent[index] == index){return index;}parent[index] = find(parent[index]);return parent[index];}
};class Solution {
public:string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {int n = s.size();UnionFind uf(n);for(auto& c : pairs){uf.unite(c[0], c[1]);}unordered_map<int, priority_queue<char, vector<char>, greater<>>> hash;for(int i = 0; i < n; i++){auto& c = s[i];hash[uf.find(i)].push(c);}string res = "";for(int i = 0; i < n; i++){res += hash[uf.find(i)].top();hash[uf.find(i)].pop();}return res;}
};

这道题首先需要掌握并查集的知识,不熟悉该数据结构的可以先去看我主页力扣990题解。这道题目我们通过观察可以发现,只要索引对之间有交互,那么这些索引对所覆盖的索引的字符之间可以通过多次交换而替换成其中的任意一个字符。通过这个特性,我们就可以将索引对之间有交集的字符作为一个连通块,连通块为了排序字符之间的字典序,所以采用了小根堆的数据结构,保证连通块之间的字符是按字典序升序排列。

那么我们最后就可以定义一个变量res来记录答案,我们只需要遍历字符串从0到n-1的索引,然后将该字符索引所在连通集中的字典序最小的字符推入到res中,然后再将最小字符从连通集的小根堆中弹出即可。

举个例子
输入:s = “dcab”, pairs = [[0,3],[1,2]]
字符d和b是一个连通集,字符c和a是一个连通集。
那么在计算res的时候,遍历字符串s,i=0所在连通集b是字典序最小字符,那么就将b推入res中,然后i=1所在连通集a是字典序最小的字符,将a推入到res中,再遍历到i=2,此时该连通集的小根堆中只剩下了c,那么只能推入c到res中,最后i=3,此时该连通集中的小根堆只剩下了d,推入d到res中,最后输出:“bacd”。


http://www.ppmy.cn/news/1573865.html

相关文章

1.3 嵌入式系统的固件

以STM32F103C8T6单片机举例&#xff0c;固件代码都是放在Flash闪存中&#xff0c;以Keil界面举例&#xff0c;该界面分为启动代码&#xff0c;库函数代码&#xff0c;还有用户代码&#xff0c;编译时&#xff0c;这些代码会被编译并链接成一个单一的固件映像&#xff0c;然后通…

C语言-进程

1、进程是什么&#xff1f; 一个具有一定独立功能的程序关于某个数据集合的一次运行活动&#xff08;程序执行的过程&#xff09;&#xff0c; 是系统进行资源分配和调度运行的基本单位。是动态的&#xff0c;随着程序的使用被创建&#xff0c;随着 程序的结束而消亡。 什么是程…

Stack和Queue—模拟实现,实战应用全解析!

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 大家好&#xff0c;我们今天来学习java数据结构的Stack和Queue&#xff08;栈和队列&#xff09; 一&#xff1a;栈 1.1&#xff1a;栈的概念 …

迪威模型网:免费畅享 3D 打印盛宴,科技魅力与趣味创意并存

还在为寻找优质3D打印模型而发愁&#xff1f;快来迪威模型网&#xff08;https://www.3dwhere.com/&#xff09;&#xff0c;一个集前沿科技与无限趣味于一体的免费3D打印宝藏平台&#xff01; 踏入迪威模型网&#xff0c;仿佛开启一场未来科技之旅。其“3D打印”专区&#xff…

【OpenCV】OpenCV 中各模块及其算子的详细分类

OpenCV 的最新版本包含了 500 多个算子&#xff0c;这些算子覆盖了图像处理、计算机视觉、机器学习、深度学习、视频分析等多个领域。为了方便使用&#xff0c;OpenCV 将这些算子分为多个模块&#xff0c;每个模块承担特定的功能。 以下是 OpenCV 中各模块及其算子的详细分类&…

“深入浅出”系列之QT:(10)Qt接入Deepseek

项目配置&#xff1a; 在.pro文件中添加网络模块&#xff1a; QT core network API配置&#xff1a; 将apiUrl替换为实际的DeepSeek API端点 将apiKey替换为你的有效API密钥 根据API文档调整请求参数&#xff08;模型名称、温度值等&#xff09; 功能说明&#xff1a; 使…

后台管理系统-月卡管理

功能说明并准备静态结构 <template><div class"card-container"><!-- 搜索区域 --><div class"search-container"><span class"search-label">车牌号码&#xff1a;</span><el-input clearable placeho…

GCC头文件搜索顺序详解

在C/C编程中&#xff0c;合理管理头文件的引入路径对于项目的组织至关重要。GCC编译器提供了灵活的机制来指定头文件的搜索路径&#xff0c;这主要通过#include "…"和#include <…>两种形式实现。本文将详细介绍这两种形式的区别以及如何使用-I参数优化头文件…