题目描述
给你一个字符串 s 以及两个整数 a 和 b 。其中,字符串 s 的长度为偶数,且仅由数字 0 到 9 组成。
你可以在 s 上按任意顺序多次执行下面两个操作之一:
累加:将 a 加到 s 中所有下标为奇数的元素上(下标从 0 开始)。数字一旦超过 9 就会变成 0,如此循环往复。例如,s = “3456” 且 a = 5,则执行此操作后 s 变成 “3951”。
轮转:将 s 向右轮转 b 位。例如,s = “3456” 且 b = 1,则执行此操作后 s 变成 “6345”。
请你返回在 s 上执行上述操作任意次后可以得到的 字典序最小 的字符串。
如果两个字符串长度相同,那么字符串 a 字典序比字符串 b 小可以这样定义:在 a 和 b 出现不同的第一个位置上,字符串 a 中的字符出现在字母表中的时间早于 b 中的对应字符。例如,"0158” 字典序比 “0190” 小,因为不同的第一个位置是在第三个字符,显然 ‘5’ 出现在 ‘9’ 之前。
示例1:
输入:s = “5525”, a = 9, b = 2
输出:“2050”
示例 2:
输入:s = “74”, a = 5, b = 1
输出:“24”
题目分析
定义队列了一个队列q,将最初的字符串入队,定义一个unordered_set 容器(无序 set 容器),用于判断字符串是否出现过,注意:unordered_set 不再以键值对的形式存储数据,而是直接存储数据的值。res字符串记录的是答案。
之后就是从队列取值,判断和res谁的字典序更小,小的赋值给res,然后对取出来的字符串累加和轮转,对新字符串判断出现过没有,没有则将其入队和更新unordered_set容器。不断重复此操作,直到队列为空。这样可以搜索出可能的字符串,取字典序最小的状态为答案。
轮转
比如:“5525” 因为轮转位数是 2
第一次:2555
第二次:5525
我们可以通过截取字符串实现一次轮转效果:s.substr(n-b)+s.substr(0,n-b)
需要用到的函数
front() 可以获得队首元素
pop() 令队首元素出队
s.substr(a) 为a开始一直到结尾截取
s.substr(a, b) 从下标为a开始截取长度为b位包括a元素
count() 函数出现次数
insert() 插入元素
emplace() 传入元素
测试代码
#include<bits\stdc++.h>
using namespace std;
int main(){
string s;
int a,b;
cin>>s>>a>>b;
//将字符串传入queue中
queue<string> q{{s}};
//unordered_set不以键值对的形式存储数据,而是直接存储数据的值
unordered_set<string> vi{{s}};
//res记录答案
string res=s;
int n=s.size();
while(!q.empty()){
//从队列中取出第一个字符串
s=q.front();
q.pop();
//与答案比较判断谁的字典序更小,更小的赋值给res
res=min(s,res);
string t1=s;
//累加
//a 加到 s 中所有下标为奇数的元素上(下标从 0 开始)
for(int i=1;i<n;i+=2){
t1[i]=(t1[i]-'0'+a)%10+'0';
}
//轮转
//通过截取字符串来进行
string t2=s.substr(n-b)+s.substr(0,n-b);
for(auto &t :{t1,t2}){
//判断新的字符串是否出现过
//没有则入队和更新vi
if(!vi.count(t)){
vi.insert(t);
q.emplace(t);
}
}
}
//输出答案
cout<<res<<endl;
return 0;
}
运行结果
另一种解法
分析
对于累加操作,数字最多累加 10 次,会回到原来的状态,轮转操作,字符串最多轮转 n次(n为字符串长度),会回到原来的状态。
如果轮转位数 b 为偶数,累加操作只会对奇数位产生影响,轮转位数 b 为奇数,累加操作既会对奇数位产生影响,也会对偶数位产生影响,
我们这样可枚举所有的字符串状态,然后取字典序最小的状态为答案。
累加十次示例
用示例一中的字符‘5’
5累加9后为4;4累加9后为3;3累加9后为2;2累加9后为1;1累加9后为0
0累加9后为9;9累加9后为8;8累加9后为7;7累加9后为6;6累加9后为5(第十次)
测试代码
#include<bits\stdc++.h>
using namespace std;
int main(){
string s;
int a,b;
cin>>s>>a>>b;
string res=s;
int n=s.size();
//轮转n次
for(int i=1;i<=n;i++){
s=s.substr(n-b)+s.substr(0,n-b);
//轮转位数 b为偶数,累加只影响奇数位
for(int j=1;j<=10;j++){
for(int k=1;k<n;k+=2){
s[k]=(s[k]-'0'+a)%10+'0';
}
//判断b是否为奇数
if(b%2!=0){
for(int j=1;j<=10;j++){
//轮转位数 b为奇数,还会对偶数维位影响
for(int k=0;k<n;k+=2){
s[k]=(s[k]-'0'+a)%10+'0';
}
//比较谁字典序小
res=min(res,s);
}
} else{
//比较谁字典序小
res=min(res,s);
}
}
}
cout<<res<<endl;
return 0;
}