问题:给出一个字符串,以及可以互换的位置对,求出互换后字典序最小的。
比如给出字符串dcab,以及可以互换的位置对[[0,3],[1, 2],[0, 2]],则互换后字典序最小的是abcd
思路:第一种方法是广度优先搜索,初始状态为dcab,将初始状态放入队列以及已经访问状态集合中,根据可以互换的位置对扩展新的状态,同时需要记录已经访问的状态。如果新的状态在已访问状态集合中则跳过。代码如下:
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <queue>
using namespace std;
struct State
{
string s;
bool operator<(const State& other) const
{
return s < other.s;
}
bool operator==(const State& other) const
{
return s == other.s;
}
};
class Solution
{
public:
Solution(string& str, vector<vector<int>>& otherPairs)
: s(str), pairs(otherPairs)
{
}
string solve()
{
State initialState;
initialState.s = s;
set<State> visited;
queue<State> queue;
visited.insert(initialState);
queue.push(initialState);
string ans = s;
while (!queue.empty())
{
State curState = queue.front(); queue.pop();
for (auto& pair : pairs)
{
State newState = curState;
char ch = newState.s[pair[0]];
newState.s[pair[0]] = newState.s[pair[1]];
newState.s[pair[1]] = ch;
if (visited.count(newState))
{
continue;
}
visited.insert(newState);
queue.push(newState);
if (newState.s < ans)
{
ans = newState.s;
}
}
}
return ans;
}
private:
string& s;
vector<vector<int>>& pairs;
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s = "dcab";
vector<vector<int>> pairs = {{0, 3}, {1, 2}, {0, 2}};
Solution solution(s, pairs);
string ans = solution.solve();
cout << ans << endl;
return 0;
}
第二种方法使用并查集,将属于同一组的排序。根据不同组排序后的结果再作合并。
代码如下:
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
class DisjointSet
{
public:
DisjointSet(const string& otherStr)
: s(otherStr)
{
for (size_t i = 0; i < s.length(); ++i)
{
parent[i] = i;
rank[i] = 0;
}
}
int Find(int x)
{
return parent[x] == x ? x : parent[x] = Find(parent[x]);
}
void Union(int x, int y)
{
int px = Find(x);
int py = Find(y);
if (px != py)
{
if (rank[px] < rank[py])
{
parent[px] = py;
}
else
{
parent[py] = px;
if (rank[px] == rank[py])
{
rank[px] += 1;
}
}
}
}
void getComponents(map<int, vector<int>>& components)
{
for (size_t i = 0; i < s.length(); ++i)
{
int p = Find(parent[i]);
components[p].push_back(i);
}
}
private:
const string& s;
map<int, int> parent;
map<int, int> rank;
};
class CmpStr
{
public:
CmpStr(const string& others)
: s(others)
{
}
bool operator()(int x, int y)
{
return s[x] < s[y];
}
private:
const string& s;
};
class Solution
{
public:
Solution(string& str, vector<vector<int>>& otherPairs)
: s(str), pairs(otherPairs)
{
}
string solve()
{
DisjointSet disjointSet(s);
for (auto& pair : pairs)
{
disjointSet.Union(pair[0], pair[1]);
}
map<int, vector<int>> components;
disjointSet.getComponents(components);
string ans = s;
for (auto& component : components)
{
auto src = component.second;
sort(src.begin(), src.end());
auto dst = component.second;
sort(dst.begin(), dst.end(), CmpStr(s));
for (size_t i = 0; i < src.size(); ++i)
{
ans[src[i]] = s[dst[i]];
}
}
return ans;
}
private:
string& s;
vector<vector<int>>& pairs;
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s = "dcab";
vector<vector<int>> pairs = {{0, 3}, {1, 2}, {0, 2}};
Solution solution(s, pairs);
string ans = solution.solve();
cout << ans << endl;
return 0;
}