1. 问题描述:
给你一个字符串 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' 之前。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lexicographically-smallest-string-after-applying-operations
2. 思路分析:
分析题目可以知道我们可以通过尝试若干次的累加与轮转操作中得到最终最小的字符串,所以一个比较容易想到的方法是使用dfs来搜索所有可能的操作下得到的字符串(也就是递归的方法),然后在这些得到的所有字符串中找到一个字典序最小的字符串即可,由题目可以知道对于当前的字符串我们可以执行两种操作,所以这里对应着两种平行状态:可以声明两个方法来模拟这两个操作,然后分别递归下去(对于每一个当前的字符串都尝试执行两个这样的操作所以可以搜索所有可能的操作对应的字符串),并且我们需要声明一个set集合来记录已经递归过的结果,这样可以提前判断当前的字符串是否之前已经递归过了,可以避免重复递归的问题
3. 代码如下:
class Solution:
def dfs(self, s: str, a: int, b: int, rec: set):
rec.add(s)
s1 = self.add(s, a)
s2 = self.rotate(s, b)
if s1 not in rec:
self.dfs(s1, a, b, rec)
if s2 not in rec:
self.dfs(s2, a, b, rec)
# 将a加到字符串中的所有奇数位置
def add(self, s: str, a: int):
n = len(s)
res = list(s)
for i in range(1, n, 2):
res[i] = str((int(s[i]) + a) % 10)
res = "".join(res)
return res
# 对字符串进行轮转操作
def rotate(self, s: str, b: int):
# 通过计算就可以知道字符串的长度为一个回合所以实际上轮转的是b % len(s)次
n = len(s)
b = b % n
return s[n - b:] + s[: n - b]
def findLexSmallestString(self, s: str, a: int, b: int) -> str:
# set集合用来记录已经记录过的结果
rec = set()
self.dfs(s, a, b, rec)
return min(rec)