【蓝桥】第八届C语言C组第7题 Excel地址(进制变形题,stack()简单使用)

标题: Excel地址

Excel单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,

当然Excel的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

本题目既是要求对输入的数字, 输出其对应的Excel地址表示方式。

例如,
输入:
26
则程序应该输出:
Z

再例如,
输入:
2054
则程序应该输出:
BZZ

我们约定,输入的整数范围[1,2147483647]

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。


笨笨有话说:
这有点像进制关系,又不完全是。好像末2位是以1当26,末3位是以1当26*26

歪歪有话说:
要是从字母序列转数字还好点,倒过来有点麻烦,不过计算机跑得快啊。

分析:
1.乍一看,像是10进制转26进制的题目,细心一琢磨,实际上这种表示方法比真实的26进制表示要多表示些内容。
2.通常的一个进制数都是有0的,这里的表示方法中也可以把A当成零,但当Z进位是到AA时,而不是直接进位到BA,这样应该就能看出来确实比一般理解的26进制多表示了一些数。
3.或者这么理解,拿16进制举例,F是15,我们假设G为16,且没有0了,那么此时十进制16的十六进制就是一个G,十进制17的十六进制是11。(要是一时理解不了,多写几个连续数转换一下,可能就捋清楚关系了)

解法1:
先来一个常见的十进制转十六进制代码对比示例:
主要分析下代码1的 n/=16; 和代码2 a=(a-yushu)/26; 的不同。

代码1:

#include <iostream>
#include <stack> 
using namespace std;
int main()
{
	int n;
	char a[6]={'A','B','C','D','E','F'};
	cin>>n;
	stack<char> b;
	if(!n) cout<<n;
	while(n)
	{
		int c=n%16;
		if(c>=10)
		{
		b.push(a[c-10]);
		}
		else
		b.push(c+'0');
		n/=16;//由于标准16进制没有一个符号单独表示16,
		//这里直接除16就好了,这是和下面代码2的关键不同之处。
	 }
	 while(!b.empty())
	 {
	 	cout<<b.top();
	 	b.pop();
	 }
	return 0;
}

代码2:(内容来源于此链接(https://www.cnblogs.com/jweie/p/8371168.html) )

#include <iostream>
using namespace std;
int main()
{
    long long a;
    int yushu;
    int b[100];
    cin>>a;
    int i=0;
    while(a)
    {
        yushu=a%26;
        if(yushu==0)yushu=26;
        a=(a-yushu)/26;//这里主要是对于a是26的倍数进行处理,这里也是和一般进制转换不同的关键之处
        //常规的26进制数是没有符号表示26的,这里的Z实际就是26,当a取模的结果是0时,也就是26,且不用进位了,
        //故在这里做除法时减去了余数(当余数是26时才有作用,别的数就算不减去也会在整数除法计算中被当成小数舍去)
        
        b[i++]=yushu;
    }
    for(int j=i-1;j>=0;j--)
    {
        printf("%c",b[j]+'A'-1);
    }
    return 0;
}

代码3:(对于代码1的stack()函数简单使用)

#include <iostream>
#include <stack>
using namespace std;
int main()
{
	
	int a; cin>>a;
	stack<char>  st; 
	while(a)
	{
		int x=a%26;
		if(x==0) x=26;
		a=(a-x)/26;
		st.push('A'+x-1);
	}
	while(!st.empty())
	{
		cout<<st.top();
		st.pop();
	}
	return 0;
}

解法2(学长代码,换一个思路看问题)

大体思路是,把每次进位的上限值放入数组val[i],从个位十位百位依次向高位处理,输入值n与各个位数上限val[i]做取模运算,并用数组ch[i]存储在每个位数上a取模的值,这里没有除法运算,直接减去上限val[i]即可。

(不明白可以提问我,当然可能你看到这篇文章时,我已经发表了很久了,久到我都忘了我发过什么了?)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

int main()
{
	ll val[20];
	char ch[20]={0};
	int n,i,tmp;
	val[0]=1;
	for(i=1;i<=7;i++){
		val[i]=26ll*val[i-1];
	}
	scanf("%lld",&n);
	for(i=0;i<=6&&n>0;i++){
		if(n%val[i+1]==0){
			ch[i]='Z';
			n-=26*val[i];
		}
		else{
			ch[i]='A'+(n%val[i+1])/val[i]-1;
			n-=n%val[i+1];
		}
	}
	for(i=6;i>=0;i--){
		if(ch[i]!=0) printf("%c",ch[i]);
	}
	printf("\n");
	return 0;
}

反向看问题:

这题算是十进制转26进制的变形题,下面这个代码正好倒过来,供大家参考
代码来源:https://blog.csdn.net/hannea/article/details/25111051

//这是一道关于进制的题目,其本质是把十进制数字用A~Z表示成二十六进制。
 
#include<iostream>
#include<string>
using namespace std;
int StringToInt(const string& str)
{
	int length = str.length();//这里也可用str.size().
 
	if(length < 0)//如果没有输入字符,则报错。
		{
			cout << "Invalid input" << endl;
			return -1;
	     }
 
	int sum = 0;//如果输入的字符为空字符,输出为0.
 
	for(int i = 0; i < length; i++)
	{
		int temp = str[i] - 'A';
		if(temp >= 26 || temp < 0)
		{
			cout << "Invalid input" << endl;
			return -1;
		}
		sum = 26*sum + temp + 1;
     }
	return sum;
 
}
int main()
{
    string str;
   while( getline(cin,str) )//这里如果用cin >> str,不能输入空的字符串。 
    cout<<str << ":" << StringToInt(str)<<endl;
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值