列表

详情


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

给你一个字符串 s 以及两个整数 ab 。其中,字符串 s 的长度为偶数,且仅由数字 09 组成。

你可以在 s 上按任意顺序多次执行下面两个操作之一:

请你返回在 s 上执行上述操作任意次后可以得到的 字典序最小 的字符串。

如果两个字符串长度相同,那么字符串 a 字典序比字符串 b 小可以这样定义:在 ab 出现不同的第一个位置上,字符串 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"

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: string findLexSmallestString(string s, int a, int b) { } };

python3 解法, 执行用时: 988 ms, 内存消耗: 33.3 MB, 提交时间: 2022-12-09 12:01:24

class Solution:
    def findLexSmallestString(self, s: str, a: int, b: int) -> str:
        n = len(s)
        b %= n
        ss = set()
        res = "1" + '0' * 101   # 最多是1e100

        def backtrace(ts):
            nonlocal res, ss

            if int(res) > int(ts):
                res = ts
            if ts in ss:  # 如果一个情况之前遇到过,说明可以终结循环了  暂时没想到减枝的方法
                return
            ss.add(ts)

            backtrace(ts[b:]+ts[:b])  # 1.先搜索旋转的情况

            ts = list(ts)
            for i in range(1, n, 2):   # 为所有奇位加上a
                ts[i] = str((int(ts[i]) + a) % 10)
            ts = ''.join(ts)

            backtrace(ts)  # 2.然后遍历奇位加上a的情况

        backtrace(s)
        return res

python3 解法, 执行用时: 1044 ms, 内存消耗: 32.2 MB, 提交时间: 2022-12-09 12:00:35

'''
模拟两个操作为子函数,暴力所有操作的结果,这里使用set存放,最后返回最小值即可,算法复杂度较高,好理解能ac
'''
class Solution:
    def findLexSmallestString(self, s: str, a: int, b: int) -> str:
        b = b%len(s)
        def addOpt(s):
            ans = [c for c in s]
            for i in range(1,len(s),2):               
                ans[i]=str((int(s[i])+a))[-1]
            return ''.join(ans)
        def lunOpt(s):
            return s[-b:]+s[:-b]
        alls = {s}  
        def dfs(s):           
            alls.add(s)          
            s1 = addOpt(s)
            s2 = lunOpt(s)          
            if s1 not in alls:                
                dfs(s1)           
            if s2 not in alls:
                dfs(s2)
        dfs(s)
        return min(alls)

cpp 解法, 执行用时: 32 ms, 内存消耗: 6.9 MB, 提交时间: 2022-12-09 11:59:39

class Solution {
public:
    string findLexSmallestString(string s, int a, int b) {
        string anw = s;
        for(int i = 0; i <= s.size(); i++) {
            // 轮转
            s = s.substr(b, s.size()) + s.substr(0, b);
            // 修改奇数位置
            for(int j = 0; j < 10; j++) {
                for(int k = 1; k < s.size(); k += 2) {
                    s[k] += a;
                    if(s[k] > '9') {
                        s[k] = '0' + (s[k]-'9'-1);
                    }
                }
                if(b%2) {
                    // b为奇数,此时通过轮转,也能修改偶数位置
                    for(int m = 0; m < 10; m++) {
                        for(int k = 0; k < s.size(); k += 2) {
                            s[k] += a;
                            if(s[k] > '9') {
                                s[k] = '0' + (s[k]-'9'-1);
                            }
                        }   
                        anw = min(anw, s);
                    }
                } else {
                    anw = min(anw, s);
                }
            }
        }
        return anw;
    }
};

cpp 解法, 执行用时: 160 ms, 内存消耗: 74.2 MB, 提交时间: 2022-12-09 11:58:30

class Solution {
public:
    string findLexSmallestString(string s, int a, int b) {
        unordered_set<string> vis;//记录已经出现的状态
        string cur, nt, minstr = s;
        int i, n = s.size(), bit;
        vis.insert(s);
        queue<string> q;
        q.push(s);
        while(!q.empty())
        {
            cur = q.front();
            q.pop();
            if(cur < minstr)
                minstr = cur;
            nt = cur;
            for(i = 1; i < n; i+=2)
            {	//奇数位加 a
                bit = (cur[i]-'0'+a)%10;
                nt[i] = bit+'0';
            }
            if(!vis.count(nt))
            {
                vis.insert(nt);
                q.push(nt);
            }
            // 向右轮转
            nt = cur.substr(n-b)+cur.substr(0,n-b);
            if(!vis.count(nt))
            {
                vis.insert(nt);
                q.push(nt);
            }
        }
        return minstr;
    }
};

cpp 解法, 执行用时: 4 ms, 内存消耗: 6.3 MB, 提交时间: 2022-12-09 11:57:50

/**
 * 暴力枚举优化
 * 事实上,对于每一个轮转,我们只需要让其第一个奇数位,也即p[1]达到最小;
 * 当然,如果可以对偶数位进行操作,则需要再考虑让p[0]达到最小。
 * 这样,对奇偶的讨论就变成了并联而非串联的关系。
 * 在确定了奇数位(和偶数位)的操作次数后,对于每一轮转,我们只会生成一个唯一的新字符串。
 **/ 
class Solution {
    int gcd(int x, int y) {
        return y == 0 ? x : gcd(y, x % y);
    }
public:
    string findLexSmallestString(string s, int a, int b) {
        int n = s.size();
        string ans = s;
        string t = s + s;
        int ga = gcd(10, a), gb = gcd(n, b);
        
        // 奇偶通用的add操作
        auto add = [&](string &p, int pos) {
            int lo = p[pos] - '0', added = 0;
            for (int i = ga; i < 10; i += ga) {
                int c = (p[pos] - '0' + i) % 10;
                if (c < lo) {
                    lo = c;
                    added = i;
                }
            }
            if (added)
                for (int i = pos; i < n; i += 2)
                    p[i] = '0' + (p[i] - '0' + added) % 10;
        };
        
        // rotate操作
        for (int i = 0; i < n; i += gb) {
            string p = t.substr(i, n);
            add(p, 1);
            if (gb % 2)
                add(p, 0);
            ans = min(ans, p);
        }
        return ans;
    }
};

cpp 解法, 执行用时: 68 ms, 内存消耗: 22.8 MB, 提交时间: 2022-12-09 11:56:20

/**
 * 暴力枚举
 * 首先考虑轮转操作。对于一个长度为N的字符串,每次轮转b个位置,等价于轮转g=GCD(N,b)个位置。
 * 所以,我们只需要以g为步长进行轮转的枚举即可。
 * 接下来考虑增加操作。如果g是偶数,那么不管怎么轮转,我们只能对下标为奇数的位置进行增加操作;
 * 否则,我们也可以对下标为偶数的位置进行增加操作。根据这两种情况,枚举奇数和偶数位置的增加操作的次数即可。
 * 因为每一位是[0,9]之间的数,而1≤a≤9,所以我们只需要枚举操作[0,9]次的情形。
 **/ 
class Solution {
    int gcd(int x, int y) {
        return y == 0 ? x : gcd(y, x % y);
    }
public:
    string findLexSmallestString(string s, int a, int b) {
        int n = s.size();
        string ans = s;
        string t = s + s;
        int g = gcd(n, b);
        for (int i = 0; i < n; i += g) {
            string p = t.substr(i, n);
            for (int j = 0; j <= 9; ++j) {
                int th = g % 2 == 0 ? 0 : 9;
                for (int k = 0; k <= th; ++k) {
                    string q(p);
                    for (int t = 1; t < n; t += 2)
                        q[t] = '0' + (q[t] - '0' + a * j) % 10;
                    for (int t = 0; t < n; t += 2)
                        q[t] = '0' + (q[t] - '0' + a * k) % 10;
                    ans = min(ans, q);
                }
            }
        }
        return ans;
    }
};

上一题