1.如何暴力解答
2.如何进行优化
题目描述
给你一个字符串 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"
解释:执行操作如下:
初态:"5525"
轮转:"2555"
累加:"2454"
累加:"2353"
轮转:"5323"
累加:"5222"
累加:"5121"
轮转:"2151"
累加:"2050"
无法获得字典序小于 "2050" 的字符串。
复制代码
示例 2:
输入:s = "74", a = 5, b = 1
输出:"24"
解释:执行操作如下:
初态:"74"
轮转:"47"
累加:"42"
轮转:"24"
无法获得字典序小于 "24" 的字符串。
复制代码
示例 3:
输入:s = "0011", a = 4, b = 2
输出:"0011"
解释:无法获得字典序小于 "0011" 的字符串。
复制代码
示例 4:
输入:s = "43987654", a = 7, b = 3
输出:"00553311"
复制代码
提示:
2 <= s.length <= 100
s.length 是偶数
s 仅由数字 0 到 9 组成
1 <= a <= 9
1 <= b <= s.length - 1
复制代码
暴力解题
本题数据量不大,暴力完全是能够解答的
但是就算是暴力,我当时也被绕晕了,暴力也不会暴力
最后仔细思考,容易理解的操作是:
一共两个操作,在任意时候都可以执行其中一个操作,两个操作也没有什么影响
因此这就像是在遍历树的左右节点即可
而终止遍历条件是该情况已经被访问过了,没必要再次访问
class Solution {
int move=0;
int rotate=0;
HashSet<String> set;
String min="";
public String findLexSmallestString(String s, int a, int b) {
set=new HashSet<>();
move=b%s.length();
rotate=a;
min=s;
Bfs(s);
return min;
}
public void Bfs(String s){
if(set.contains(s)){
//System.out.println("被访问过了,停止访问");
return;
}
set.add(s);
//s是新的字符串,因此比较是不是最小的
min=getMinString(min,s);
//进行move操作
Bfs(moveToNewStringBuffer(new StringBuffer(s)));
//进行rotate操作
Bfs(rotateToNewString(new StringBuffer(s)));
}
public String getMinString(String s1,String s2){
if(s1.compareTo(s2)<=0){
return s1;
}else {
return s2;
}
}
public String moveToNewStringBuffer(StringBuffer sb){
for (int i = 0; i < move; i++) {
sb.insert(0,sb.charAt(sb.length()-1));
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
public String rotateToNewString(StringBuffer sb){
for (int i = 1; i < sb.length(); i=i+2) {
char c= (char) ((sb.charAt(i)-'0'+rotate)%10+'0');
sb.setCharAt(i,c);
}
return sb.toString();
}
}
复制代码
优化
首先考虑b%2==0的情况,此时我们无论怎么加a也只能对奇数坐标下的增加
我们令移动操作为m,旋转操作为r,最优解一定是通过m和r的组合得到的,而r无论放在哪里都是对奇数坐标的那些加减 m r m m r r m ...
也就是说m r r和r r m得到的结果是一样的
因此我们可以直接让String s 移动0个a距离,1个a距离...直到再次等于s
在这个过程中我们在选择1个r,2个r...到10个r,因为,旋转10次就会重复
如果b%2==1是,我们把数组分为a b两个部分,显然在最开始的时候我们进行r操作时,只有b部分动了
但是我们移动b的话,再进行r操作,a部分动了
而且a动不影响b动
我们可以这样想,现在情况为这样,我们移动b下,然后把a调成最好的情况,再移动n下回到现在整个位置
如果摒弃了整个复杂的过程,是不是相当于a也可以旋转了
因此现在的条件变成,a,b是独立可以旋转的
因此我们先把a旋转最大,再把b旋转最大,这就是当前最好情况
然后我们再进行m操作即可
再举例子说明一下: r1代表移动了a部分 r2移动了b部分 和m操作
r2 r2 r2 m m m r1 r1 m r2 m r1 r1 r1 m m m r2 r2 r2
这不就是移动了8个m 5个r1 7个r2吗 我们完全覆盖了这种情况,而且还能够优化不必要的计算,例如我们只需要组合r1最好和r2最好情况,对于r1和r2不好情况的组合不用考虑的
class Solution {
int move=0;
int rotate=0;
public String findLexSmallestString(String s, int a, int b) {
String min=s;
String begin=s;
move=b;
rotate=a;
//if(b%2==1)move=1;
boolean flag=true;
while (!begin.equals(s)||flag){
flag=false;
String rotate=begin;
if(b%2==1){
String temp=rotate;
for (int i = 0; i < 11; i++) {
min=getMinString(min,rotate);
temp=getMinString(temp,rotate);
rotate=rotateToNewString1(new StringBuffer(rotate));
}
rotate=temp;
for (int i = 0; i < 11; i++) {
min=getMinString(min,rotate);
rotate=rotateToNewString(new StringBuffer(rotate));
}
}else {
for (int i = 0; i < 11; i++) {
min=getMinString(min,rotate);
rotate=rotateToNewString(new StringBuffer(rotate));
}
}
begin=moveToNewStringBuffer(new StringBuffer(begin));
}
return min;
}
public String getMinString(String s1,String s2){
if(s1.compareTo(s2)<=0){
return s1;
}else {
return s2;
}
}
public String moveToNewStringBuffer(StringBuffer sb){
for (int i = 0; i < move; i++) {
sb.insert(0,sb.charAt(sb.length()-1));
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
public String rotateToNewString(StringBuffer sb){
for (int i = 1; i < sb.length(); i=i+2) {
char c= (char) ((sb.charAt(i)-'0'+rotate)%10+'0');
sb.setCharAt(i,c);
}
return sb.toString();
}
public String rotateToNewString1(StringBuffer sb){
for (int i = 0; i < sb.length(); i=i+2) {
char c= (char) ((sb.charAt(i)-'0'+rotate)%10+'0');
sb.setCharAt(i,c);
}
return sb.toString();
}
}
复制代码