执行操作后字典序最小的字符串

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();
    }

}
复制代码

Guess you like

Origin juejin.im/post/7039533589993619464