1625. 执行操作后字典序最小的字符串(力扣)

文章介绍了如何通过使用队列和无序集合数据结构,结合字符串的累加和轮转操作,寻找给定条件下字典序最小的字符串。两种解法分别利用了队列和双重循环来遍历所有可能的状态,并通过比较取字典序最小的字符串作为答案。
摘要由CSDN通过智能技术生成

题目描述

给你一个字符串 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;
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yjg_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值