leetcode题库学习系列——168. Excel表列名称

原题地址:
https://leetcode-cn.com/problems/excel-sheet-column-title/

原题如下:

给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。

例如:

A -> 1
B -> 2
C -> 3

Z -> 26
AA -> 27
AB -> 28

示例 1:

输入:columnNumber = 1
输出:“A”
示例 2:

输入:columnNumber = 28
输出:“AB”
示例 3:

输入:columnNumber = 701
输出:“ZY”
示例 4:

输入:columnNumber = 2147483647
输出:“FXSHRXW”

提示:

1 <= columnNumber <= 231 - 1



记录解题思路:

打眼看去是个26进制的题(想到这点的思路很快,这算是我的一个进步),同时应该很快的联想到进制的换算,以10进制为枢纽,10进制写成N进制,M进制写成10进制等等,应该马上联想到这些才对。
然后进行了区域演算,如下:
A=1
Z=26
AA=27=1+26*1
AZ=52
BA=53=1+26*2=B*26^1+A*26^0
BZ=78=B*26^1+Z*26^0
ZA=1+26*26=677
ZZ=702=Z*26^1+Z*26^0
……
A~Z有26个字母,A和Z的索引相差25等信息也随之而来。
看起来就是进制运算,题目也就是将10进制数字转化成26进制,那么用短除笔算,发现了大问题。
比如ZZ=702在转化成26进制数字的时候,结果等于110,变换对应字符,是AA0,并不是ZZ;
比如BZ=78,转化结果为30,变换对应字符,是C0,也不是BZ。

此时我发现,原文中A~Z是1~26,没有0,这里知道出现问题了,同时也发现了问题规律,就是如果得到了AA0,那么减1就是ZZ;如果得到了C0,减1就是BZ,但问题是我们知道AA0可以减1,但是计算机代码不知道AA0是什么,这是我们为了解题而思考出来的26进制表示方法,另外,是不是A0A0就要减2了呢?

这里卡住了我很久,原因就是我固执地想把得到的结果AA0怎样处理一下,就可以得到真正的结果ZZ,因为我脑中的思路就是10进制转化26进制的过程,这个过程是神圣不可侵犯的,不可更改的,所以我想当然的要从结果AA0入手去转换为ZZ,这困扰了我很久,因为我找不到一个能说服我的转换思路,不论是遇到0就减1还是其他的什么。

后来我仔细分析了一下短除的过程,为什么会出现0这个余数,怎样能得到正确的结果,我用最基础的Z=26来除以26重新短除捋思路,发现26短除26的第一阶,商为1,余数就为0,然后考虑题中A为1,那么0应该就是A的前一个字符Z,Z也即是26所指,问题是还有一个商1没有被除尽,然后思考了一下题目并不是完整的10进制转换为26进制的问题,原题本身就少了0这个因子,所以把这个商减1处理,既在形式上得到了正确的结果,也在意义上算是补充低位的0形成Z这个值。

因此,短除多了一个重要的,针对于该题的步骤:
当短除到某阶,余数为0时,此时将商减1处理,继续短除直至商为0。余数为0的对应字符为Z。

代码如下:

class Solution {

    private char int2Char(int letterInt){
        return (char)(64+(letterInt==0?26:letterInt));
    }
  
    public String convertToTitle(int columnNumber) {
       StringBuffer sb=new StringBuffer();
        int shang=0;
        int chushu=columnNumber;
        do{
            shang=chushu/26;
            int yushu=chushu%26;
            if(yushu==0)
            {
                shang--;
            }
            sb.append(int2Char(yushu));
            chushu=shang;
        }while(shang!=0);
        return sb.reverse().toString();
    }
    
}

看到一个消耗内存最少的大神的代码如下:
值得学习

class Solution {
    public String convertToTitle(int n) {
	StringBuilder stringBuilder = new StringBuilder();
	while (n != 0) {
		n--; // 依次获取 26 进制逻辑上的个位、十位、百位…(虽然在 26 进制中不这么叫)
		stringBuilder.append((char) ('A' + n % 26));
		n /= 26;
	}
	return stringBuilder.reverse().toString();
    }
}

反思

卡了很久的地方,为了尽快解题而选择碰运气来处理result,是不对的,应该回归解题思路与步骤,从步骤中寻找突破口。

上一篇:Hashtable的方法是同步的、线程安全的;HashMap的方法不是同步的、线程不安全。HashMap效率较高,Hashtable效率较低。


下一篇:LeetCode 167 两数之和