本文涉及知识点
C++图论
并集查找(并查集)
LeetCode1202. 交换字符串中的元素
给你一个字符串 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 <= 105
0 <= pairs.length <= 105
0 <= pairs[i][0], pairs[i][1] < s.length
s 中只含有小写英文字母
并集查找
把下标(索引)看做点,paris看成边。一个连通区域的下标可以任意改变。将各连通区域的字典序排序便是答案。
代码
核心代码
class CUnionFind
{
public:
CUnionFind(int iSize) :m_vNodeToRegion(iSize)
{
for (int i = 0; i < iSize; i++)
{
m_vNodeToRegion[i] = i;
}
m_iConnetRegionCount = iSize;
}
CUnionFind(vector<vector<int>>& vNeiBo):CUnionFind(vNeiBo.size())
{
for (int i = 0; i < vNeiBo.size(); i++) {
for (const auto& n : vNeiBo[i]) {
Union(i, n);
}
}
}
int GetConnectRegionIndex(int iNode)
{
int& iConnectNO = m_vNodeToRegion[iNode];
if (iNode == iConnectNO)
{
return iNode;
}
return iConnectNO = GetConnectRegionIndex(iConnectNO);
}
void Union(int iNode1, int iNode2)
{
const int iConnectNO1 = GetConnectRegionIndex(iNode1);
const int iConnectNO2 = GetConnectRegionIndex(iNode2);
if (iConnectNO1 == iConnectNO2)
{
return;
}
m_iConnetRegionCount--;
if (iConnectNO1 > iConnectNO2)
{
UnionConnect(iConnectNO1, iConnectNO2);
}
else
{
UnionConnect(iConnectNO2, iConnectNO1);
}
}
bool IsConnect(int iNode1, int iNode2)
{
return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);
}
int GetConnetRegionCount()const
{
return m_iConnetRegionCount;
}
vector<int> GetNodeCountOfRegion()//各联通区域的节点数量
{
const int iNodeSize = m_vNodeToRegion.size();
vector<int> vRet(iNodeSize);
for (int i = 0; i < iNodeSize; i++)
{
vRet[GetConnectRegionIndex(i)]++;
}
return vRet;
}
std::unordered_map<int, vector<int>> GetNodeOfRegion()
{
std::unordered_map<int, vector<int>> ret;
const int iNodeSize = m_vNodeToRegion.size();
for (int i = 0; i < iNodeSize; i++)
{
ret[GetConnectRegionIndex(i)].emplace_back(i);
}
return ret;
}
private:
void UnionConnect(int iFrom, int iTo)
{
m_vNodeToRegion[iFrom] = iTo;
}
vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引
int m_iConnetRegionCount;
};
class Solution {
public:
string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
const int N = s.length();
CUnionFind uf(N);
for (const auto& v : pairs) {
uf.Union(v[0], v[1]);
}
vector<vector<int>> v(N);
for (int i = 0; i < N; i++) {
v[uf.GetConnectRegionIndex(i)].emplace_back(s[i]);
}
for (auto& v1 : v) {
sort(v1.begin(), v1.end(), greater<>());
}
string ans;
for (int i = 0; i < N; i++) {
auto& v1 = v[uf.GetConnectRegionIndex(i)];
ans += v1.back();
v1.pop_back();
}
return ans;
}
};
单元测试
string s;
vector<vector<int>> pairs;
TEST_METHOD(TestMethod11)
{
s = "dcab", pairs = { {0,3},{1,2} };
auto res = Solution().smallestStringWithSwaps(s, pairs);
AssertEx(string("bacd"), res);
}
TEST_METHOD(TestMethod12)
{
s = "dcab", pairs = { {0,3},{1,2},{0,2} };
auto res = Solution().smallestStringWithSwaps(s, pairs);
AssertEx(string("abcd"), res);
}
TEST_METHOD(TestMethod13)
{
s = "cba", pairs = { {0,1},{1,2} };
auto res = Solution().smallestStringWithSwaps(s, pairs);
AssertEx(string("abc"), res);
}
TEST_METHOD(TestMethod14)
{
s = "dqwyt", pairs ={ {2,3},{3,2},{0,1},{4,0},{3,2} };
auto res = Solution().smallestStringWithSwaps(s, pairs);
AssertEx(string("abc"), res);
}