AT_agc022_a 题解

发布时间 2023-07-29 09:52:50作者: So_noSlack

洛谷链接&Atcoder 链接

本篇题解为此题较简单做法较少码量,并且码风优良,请放心阅读。

题目简述

给定字符串 \(S\) , 仅包含互不相同的小写字母, 你需要找到仅包含互不相同的小写字母的字符串中,第一个字典序比它大的字符串, 如果找不到输出 \(-1\)。(\(| S | \le 26\)

思路

这篇题解主要分享一下 map 的做法。

可分两种情况讨论:

  1. 字符串长度 \(< 26\)

  2. 字符串长度 \(= 26\)

因为互不相同所以不会出现大于 \(26\) 的情况。

对于样例 \(4\)abcdefghijklmnopqrstuvwzyx

可将 w 变为它后面比它大但最小x,后面直接舍去即可,变为 abcdefghijklmnopqrstuvx

解释完样例,先来讨论一下情况 \(1\),因为长度小于 \(26\),所以至少有 \(1\) 个字母未出现过,直接在字符串末尾加上没出现过最小字母即可。

对于情况 \(2\),就可参考以上样例 \(4\) 的解释,可发现找到一个位置,把这个位置上的字母替换为它后面比它大但最小的字母即可,这个位置需要从后向前枚举

那么接下来就是实现了,首先需要定义一个 map 容器,来存储哪些字母出现过或没出现过,对于情况 \(1\) 直接模拟即可。

对于情况 \(2\) 则需记录一个最大值,如果当前位置小于最大值再枚举,这样就避免了不合法的情况了。

经过以上分类讨论,很容易即可写出代码了:

#include<iostream>
#include<map>
using namespace std;

string str;
int maxn;
map<char, int> mp;
map<int, bool> vis;

int max(int x, int y) { return (x > y) ? x : y; }

int main() {
	cin >> str;
	int n = str.length(); // 记录长度
	for(int i = 0; i < n; i ++) mp[str[i]] ++; // 计数
	if(n < 26) {
		for(int i = 'a'; i <= 'z'; i ++) 
			if(!mp[i]) {
				cout << str << char(i) << endl; // 没有出现过,直接输出结束
				return 0;
			}
	}
  	// 从后向前枚举
	for(int i = n - 1; i >= 0; i --) {
  		// 满足条件,可输出
		if(str[i] < maxn) {
			for(int j = 0; j < i; j ++) cout << str[j];
			for(int j = str[i] - 'a'; j < 26; j ++) 
				if(vis[j]) {
					cout << char(j + 'a'); // 输出替换的字母
					return 0;
				}
		}
		maxn = max(maxn, str[i]);
		vis[str[i] - 'a'] = true;
	}
	cout << "-1\n"; // 以上条件都不满足,输出 -1
	return 0;
}

提交记录

\[\text{The End!} \]