砹小翼的园子

达则兼济天下,穷则独善其身。

导航

[Java] [刷题] Excel地址转换

题目

将一个整数转换为Excel的列号,整数范围为[1, 2147483647]。

Excel的单元格中,列号表示如下:
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,
……

I/O 样例1 样例2
输入 26 2054
输出 Z BZZ

来源

蓝桥杯2012年高职高专组JAVA组 决赛第4题
蓝桥杯2012年高职高专组C语言组 决赛第3题

解题思路

从题目附加描述中的“列号”可以看出,这一题应该用“进制转换”的解法,即除n求余倒插(n为进制数),但这题的坑在于——Excel的列号没有0

十六进制符号有0到F十六个,分别代表0到15;Excel列号的符号有A到Z二十六个,按描述来说分别代表1到26,显然没有0。没有0的话不能按常规进位制算法处理,于是在前期将A到Z对应成0到25,再在后期“+1”,对应回原来的1到26。

假设在前期的处理中,A对应0,Z对应25,那么Z+1(即25+1==26)对应什么呢?再进一步,假设此时存在列号“AA”,那么它的两个A是代表十进制数的0还是1呢?

那么对题目附加描述进行分析,可以得到下表:

列号 十进制数 分解算式 分解算式++
A 1 1 26 * 0 + 1 * 1
B 2 2 26 * 0 + 1 * 2
AA 27 26+1 26 * 1 + 1 * 1
AB 28 26+2 26 * 1 + 1 * 2
BA 53 52+1 26 * 2 + 1 * 1
按照正常进制算法用短除法分析样例中的2054,得到
2054 == 676*3 + 26*1 + 1*0,对照ASCII表得到的CA@DBA都是错的。

因为Excel的列号没有0,于是按照进位制的思想向前借一,得到
2054 == 676*3 + 26*0 + 1*26,仍然有0。

于是再向前借一,得到
2054 == 676*2 + 26*26 + 1*26,对照ASCII表得到BZZ,正确!

我的实现

package top.qlin.leo;
import java.util.Scanner;

public class Main {
    /** ASCII表中字符A的前一个字符,代表进位制中的0。用于判断分解的结果中是否有0。 */
    final static char FLAG = 'A' - 1;

    public static void main(String[] args) {
        // 使用Scanner从输入流中获取等待被转换为Excel的整数num:
        Scanner sr = new Scanner(System.in);
        int num = sr.nextInt();
        sr.close();

        // 为了提升效率,使用StringBuffer存放结果:
        StringBuffer n26bf = new StringBuffer();

        // N进制转十进制的算法:
        // 将整数num除以二十六进制的进制数26,将余数转换为字母,插入到StringBuffer的位置0中(即先出现的余数放到结果的右端,后出现的余数放到左端);将商作为整数num送入下一循环再次运算。
        while (num > 0) {
            n26bf.insert(0, (char) ((num % 26) + 64));
            num /= 26;
        }

        // 将结果转换为字符数组:
        char[] n26cs = n26bf.toString().toCharArray();

        // 从结果的右端(最后一位数)循环遍历到左端(第二位数),若有0则向前借一:
        for (int i = n26cs.length - 1; i > 0; i--) {
            if (n26cs[i] == FLAG) {
                n26cs[i] += 26;
                n26cs[i - 1]--;
            }
        }

        // 借位完毕后,如果第一位为0,则只需从第二位开始输出。
        if (n26cs[0] == FLAG) {
            System.out.print(String.valueOf(n26cs).substring(1, n26cs.length));
        } else {
            System.out.print(String.valueOf(n26cs));
        }
    }
}

posted on 2020-01-20 15:09  砹小翼  阅读(280)  评论(0编辑  收藏  举报