持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。
C. Phase Shift
中文大意
有一个字符串s,它应该被加密。为此,所有26个小写英文字母按一定的顺序排列在一个圆圈中,之后,s中的每个字母按顺时针顺序被替换成后面的字母,这样就得到了字符串t。 给你一个字符串t,请确定从词典上看最小的字符串s可能是所给字符串t的原型。 一个字符串a在词典上比相同长度的字符串b小,当且仅当。 在a和b不同的第一个位置,字符串a有一个字母,该字母在字母表中出现的时间比b中的相应字母早。
题意
将26个英文字母构成一个环让给的字符串S是根据这个环上的顺序由字典序最小的字符串T得到
因为是要求最小的字典序所以我们采用贪心的思想将字符串S从前往后遍历与字符a~z构成映射
例如题目所给的样例
值得注意的一点就是我们在映射的过程住要注意在我们形成的映射环中如果没有到达26个字母就形成了环这个是不符合的所以在构造映射的过程中我们使用并查集去判环
rep(i,n) {
int x = s[i] - 'a' + 1;
if(a[x] == 0) {
for(int idx = 1; idx <= 26; idx++)
{
if(vis[idx]) continue;
if(idx == x) continue;
if(find(x) == find(idx)) continue;//判环
a[x] = idx;
f[find(x)] = find(idx);
st.erase('a' + idx - 1);
vis[idx] = true;
break;
}
}
}
在构造的过程中为了防止我们重复的使用字母我们用一个vis数组去记录这个字母有没有被使用过
又因为我们我们是要映射构成一个环但是我们在映射过程中又进行的判环所以当字符字符串S映射结束后
我们所构造的映射是首尾不相连的为了解决这个问题知道最后没有相连的首位我们采用set每映射成一组我们就从set中删除对应的最后剩下的肯定是首尾没有构成映射的肯定是末尾的字母我们只需最后手动添加一下即可
Code
char s[N];
int f[N];
int find(int x) {return f[x] == x ? f[x]: f[x] = find(f[x]);}
void solve()
{
int n; cin >> n;
rep(i,n) cin >> s[i];
rep(i,26) f[i] = i;
vector<int> a(30,0);
bool flag = false;
int num = 0;
vector<bool> vis(30,false);
set<char> st;
for(char i = 'a'; i <= 'z'; i++) st.insert(i);
rep(i,n) {
int x = s[i] - 'a' + 1;
if(a[x] == 0) {
for(int idx = 1; idx <= 26; idx++)
{
if(vis[idx]) continue;
if(idx == x) continue;
if(find(x) == find(idx)) continue;//判环
a[x] = idx;
f[find(x)] = find(idx);
st.erase('a' + idx - 1);
vis[idx] = true;
break;
}
}
}
rep(i,26) if(!a[i]) a[i] =*st.begin() - 'a' + 1;
// if(flag) a[26] = 1;
char res = 'a';
rep(i,n) cout << char(res - 1 +a[s[i] - 'a' + 1]);
cout << endl;
}