题意
咕咕东是个贪玩的孩子,有一天,他从上古遗迹中得到了一个神奇的圆环。这个圆环由字母表组成首尾相接的环,环上有一个指针,最初指向字母a。咕咕东每次可以顺时针或者逆时针旋转一格。例如,a顺时针旋转到z,逆时针旋转到b。咕咕东手里有一个字符串,但是他太笨了,所以他来请求你的帮助,问最少需要转多少次。
Input
输入只有一行,是一个字符串。
Output
输出最少要转的次数。
输入样例
zeus
输出样例
18
提示
分析
一般第一题都并不复杂,思考一会儿会发现规律。
- 题目理解
题目希望求解的是得到一个字符串的最少转动次数。
首先得清楚,指针不会动,而是整个字母圈转动。依次将字符串中的字符转到指针下,即为生成一个字符串。而这个过程中,每次只能将指针逐个字母转动(比如从a到b)。最后按顺序转到所有字母后得到总的转动次数。
- 题目分析
显然字母圈是按照字母表顺序排列,形成的首尾相接的序列。转动的时候可以选择顺时针或者逆时针。
为了使总转动次数最少就要使每一次转动的次数最少。显然,向目标字符离当前指针指向字符更近的方向转动时,转动次数最少。
那么问题关键就在于如何确定指针指向字符在哪个方向离目标字符更近。
- 实现思路
最开始有想过用一些数据结构来实现循环序列,例如队列、数组等。
但是在过程中发现这个想法有点不太顺畅,并且突然醒悟。由于字母圈中的所有字符均按顺序排列,因此任意两个字符之间的单向距离即为它们ascii码之差的绝对值。(根据圆盘顺序,可知此处单向距离即为顺时针距离)
当我们在用肉眼观察的时候能很快分辨在哪个方向两个字符更接近。其实这就等于是在观察目标字符分布在字母圈的哪一半。
显然当两者的距离小于整个字母圈周长的一半时,目标字符就在右半边,即在顺时针方向两者更接近。同理,当两者距离大于周长一半时,在逆时针方向更接近。而字母圈的周长就可以用字母的总个数来代替。
于是问题就变得简单了起来🙋:
-
记录当前指向的字符与目标字符
-
将字符转位ascii码并求得其差的绝对值
-
将绝对值与字母个数的一半进行比较
- 若小于,则应顺时针转动
- 若大于,则应逆时针转动
- 若等于,则两方向都可
而由于我们要求的是最少的转动次数,所以就可以将判断后的操作改为将ascii码的差叠加到总次数中,还是将字母个数与ascii码差值的差叠加到次数中。(因为如果是逆时针旋转的话,其转动次数就是周长中剩余部分)
总结
- 总结规律更快一点就好啦
- 写代码的时候别着急!虽然一限时就害怕😢
代码
//
// main.cpp
// lab1
//
//
#include <iostream>
#include <queue>
#include <list>
#include <string>
using namespace std;
//queue<char> q;
int main()
{
ios::sync_with_stdio(false);
string s; //获得字符串
cin>>s;
int start = 0,length = 26,result = 0;
// for( int i = 97 ; i <= 122 ; i++ ) //将所有小写字符压入队列中
// q.push(char(i));
//因为所有字符都是按大小顺序a逐个循环摆放
//所以两个字符之间转动的最少次数,即为在循环顺序中,两个字符的最小距离
//因此可以利用两个字符的ascii码差值进行计算
for( int i = 0 ; i < s.size() ; i++ )
//依次遍历输入字符串中国呢的每个字符
//第一个字符一定是与a比较
//将所有字符的ascii码-97,意味着字母a从0开始
{
int end = s[i] - 97 ; //计算字符代表值
// cout<<end<<"--------"<<endl;
int mid = start - end; //计算当前字符与上一次指向字符之间的差值(即为距离)
if( mid < 0 ) //保证其永远为正数
mid = -mid;
if( mid > 13 ) //若距离小于13(即最大距离的1/2),则为最小距离
result += length - mid;
else if( mid < 13 ) //若大于13,说明相反方向距离为最小距离,即为总距离与该距离的差值
result += mid;
else //若等于13,则最大最小距离皆等于13
result += mid;
// cout<<result<<"&&"<<endl;
start = end; //指向当前字符
}
cout<<result<<endl; //最少转动次数即为每个字符与前一个字符的最小距离之和
return 0;
}