comments | difficulty | edit_url | rating | source | tags | ||||
---|---|---|---|---|---|---|---|---|---|
true |
中等 |
1992 |
第 211 场周赛 Q2 |
|
给你一个字符串 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" 的字符串。
提示:
2 <= s.length <= 100
s.length
是偶数s
仅由数字0
到9
组成1 <= a <= 9
1 <= b <= s.length - 1
本题数据规模较小,我们可以使用 BFS 暴力搜索所有可能的状态,然后取字典序最小的状态即可。
class Solution:
def findLexSmallestString(self, s: str, a: int, b: int) -> str:
q = deque([s])
vis = {s}
ans = s
while q:
s = q.popleft()
if ans > s:
ans = s
t1 = ''.join(
[str((int(c) + a) % 10) if i & 1 else c for i, c in enumerate(s)]
)
t2 = s[-b:] + s[:-b]
for t in (t1, t2):
if t not in vis:
vis.add(t)
q.append(t)
return ans
class Solution {
public String findLexSmallestString(String s, int a, int b) {
Deque<String> q = new ArrayDeque<>();
q.offer(s);
Set<String> vis = new HashSet<>();
vis.add(s);
String ans = s;
int n = s.length();
while (!q.isEmpty()) {
s = q.poll();
if (ans.compareTo(s) > 0) {
ans = s;
}
char[] cs = s.toCharArray();
for (int i = 1; i < n; i += 2) {
cs[i] = (char) (((cs[i] - '0' + a) % 10) + '0');
}
String t1 = String.valueOf(cs);
String t2 = s.substring(n - b) + s.substring(0, n - b);
for (String t : List.of(t1, t2)) {
if (vis.add(t)) {
q.offer(t);
}
}
}
return ans;
}
}
class Solution {
public:
string findLexSmallestString(string s, int a, int b) {
queue<string> q{{s}};
unordered_set<string> vis{{s}};
string ans = s;
int n = s.size();
while (!q.empty()) {
s = q.front();
q.pop();
ans = min(ans, s);
string t1 = s;
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}) {
if (!vis.count(t)) {
vis.insert(t);
q.emplace(t);
}
}
}
return ans;
}
};
func findLexSmallestString(s string, a int, b int) string {
q := []string{s}
vis := map[string]bool{s: true}
ans := s
n := len(s)
for len(q) > 0 {
s = q[0]
q = q[1:]
if ans > s {
ans = s
}
t1 := []byte(s)
for i := 1; i < n; i += 2 {
t1[i] = byte((int(t1[i]-'0')+a)%10 + '0')
}
t2 := s[n-b:] + s[:n-b]
for _, t := range []string{string(t1), t2} {
if !vis[t] {
vis[t] = true
q = append(q, t)
}
}
}
return ans
}
我们观察发现,对于累加操作,数字最多累加
因此,轮转操作最多产生
所以,我们直接枚举所有的字符串状态,取字典序最小的状态即可。
时间复杂度
class Solution:
def findLexSmallestString(self, s: str, a: int, b: int) -> str:
ans = s
n = len(s)
s = list(s)
for _ in range(n):
s = s[-b:] + s[:-b]
for j in range(10):
for k in range(1, n, 2):
s[k] = str((int(s[k]) + a) % 10)
if b & 1:
for p in range(10):
for k in range(0, n, 2):
s[k] = str((int(s[k]) + a) % 10)
t = ''.join(s)
if ans > t:
ans = t
else:
t = ''.join(s)
if ans > t:
ans = t
return ans
class Solution {
public String findLexSmallestString(String s, int a, int b) {
int n = s.length();
String ans = s;
for (int i = 0; i < n; ++i) {
s = s.substring(b) + s.substring(0, b);
char[] cs = s.toCharArray();
for (int j = 0; j < 10; ++j) {
for (int k = 1; k < n; k += 2) {
cs[k] = (char) (((cs[k] - '0' + a) % 10) + '0');
}
if ((b & 1) == 1) {
for (int p = 0; p < 10; ++p) {
for (int k = 0; k < n; k += 2) {
cs[k] = (char) (((cs[k] - '0' + a) % 10) + '0');
}
s = String.valueOf(cs);
if (ans.compareTo(s) > 0) {
ans = s;
}
}
} else {
s = String.valueOf(cs);
if (ans.compareTo(s) > 0) {
ans = s;
}
}
}
}
return ans;
}
}
class Solution {
public:
string findLexSmallestString(string s, int a, int b) {
int n = s.size();
string ans = s;
for (int i = 0; i < n; ++i) {
s = s.substr(n - b) + s.substr(0, n - b);
for (int j = 0; j < 10; ++j) {
for (int k = 1; k < n; k += 2) {
s[k] = (s[k] - '0' + a) % 10 + '0';
}
if (b & 1) {
for (int p = 0; p < 10; ++p) {
for (int k = 0; k < n; k += 2) {
s[k] = (s[k] - '0' + a) % 10 + '0';
}
ans = min(ans, s);
}
} else {
ans = min(ans, s);
}
}
}
return ans;
}
};
func findLexSmallestString(s string, a int, b int) string {
n := len(s)
ans := s
for _ = range s {
s = s[n-b:] + s[:n-b]
cs := []byte(s)
for j := 0; j < 10; j++ {
for k := 1; k < n; k += 2 {
cs[k] = byte((int(cs[k]-'0')+a)%10 + '0')
}
if b&1 == 1 {
for p := 0; p < 10; p++ {
for k := 0; k < n; k += 2 {
cs[k] = byte((int(cs[k]-'0')+a)%10 + '0')
}
s = string(cs)
if ans > s {
ans = s
}
}
} else {
s = string(cs)
if ans > s {
ans = s
}
}
}
}
return ans
}