[Leetcode]Excel Sheet Column Title/Number

这是两道easy类别的题。相比之下,Title比Number要稍难(稍麻烦),提交的正确率也更低。

这两个题的要求是互逆的,灵感来自于Excel的列标和列数的转换。不知最初为何要这样设计,Excel的列从A开始往后编号,Z之后是AA,AZ之后是BA,ZZ之后是AAA……

先从简单的Number说起。显然转换规则很像是26进制,但还不是真正的26进制。规律如下。

A <-> 1

B <-> 2

...

Z <-> 26

AA <-> 27 ( 26 * 1 + 1 )

...

AZ <-> 52 (26 * 1 + 26)

BA <-> 53((26 ^ 1) * 2 + 1)

...

ZZ <-> 702 ((26  ^ 1) * 26 + 26)

AAA <-> 703 ((26 ^ 2) * 1 + (26 ^ 1) * 1 + 1)

....

真正的26进制,26的次幂的乘数最大应是25。但这个问题里可以到26。

代码如下(Python):

class Solution:
    # @param s, a string
    # @return an integer
    def titleToNumber(self, s):
        ret = 0
        s = s[::-1]
        pwr = 1
        for x in s:
            #ret = ret + pwr * self.alphabet.index(x)
	    ret = ret + pwr * (ord(x) - 64) 
            pwr *= 26
        return ret
    #alphabet = ('','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',)
sol = Solution()
print sol.titleToNumber('CFDGSXM') #1000000001


 

首先把s翻转过来,pwr是26的次幂,然后按照前面的转换方法进行转换。

C++用反向迭代器就可以逆序字符串:

class Solution {
public:
    int titleToNumber(string s) {
        int ret = 0;
        int pwr = 1;
        for(string::reverse_iterator i=s.rbegin();i!=s.rend();i++){
            ret = ret + pwr * (*i - 'A' + 1);
            pwr *= 26;
        }
        return ret;
    }
};


稍微复杂一点的Title。

刚开始我把整个问题都想复杂了。上面的转换模式也不是一开始就想到。我是从0开始算的,因为观念中进制转换就要从0开始,但是除了最低位,其他位都是从1开始,26结束,导致整个转换模式不统一。

Python:

class Solution:
    # @return a string
    def convertToTitle(self, num):
        i = 1
        ret = ""

        while num > self.Power26Sum[i]: i += 1
        i -= 1

        while i > 0:
            q = num / self.Power26[i]
            num = num - q * self.Power26[i]
            if num <= self.Power26Sum[i-1]:
                q -= 1
                num += self.Power26[i]
            ret += self.alphabet[q]
            i -= 1

        return ret + self.alphabet[num]

    Power26Sum = (0,26,702,18278,475254,12356630,321272406,0x7fffffff)
    Power26 = (1,26,676,17576,456976,11881376,308915776)
    alphabet = ('','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',)


sol = Solution()
for i in range(10000):
    print sol.convertToTitle(i)

类中定义了元组Power26,表示26的次幂(都在int范围内);元组Power26Sum,表示26的次幂和,即Power26Sum[i] = Power26Sum[i-1] + Power26[i];元组alphabet作为整数和字符的转换。Power26的最后一个元素特别设为最大整数值,以防越界。

进入convertToTitle,首先确定这个数是在哪个Power26Sum区间内(也就是有几个字母)。然后不断进行类似于26进制转10进制的操作。稍有不同的是,加入一个if判断。因为如果不加可能出现如下情况。比如AZZ对应((26^2) * 1+ (26^1) * 26 + 26 = 1378)。这样在转换时,第一次循环:q = 1378 / 676 = 1, num = 1378 - 676 * 1 = 702,ret +=‘A’;第二次循环q= 702 / 26 = 27, num = 702 - 26 * 27 = 0,alphabet数组越界(即使用chr(q+64)进行转换也超出了‘Z‘)。原因在于如果(剩余的)num小于低一次幂的26次幂和(比如0 <= 0),说明这一步减多了,需要补回来。ZZ把第一个Z对应的数减下去,剩余至少应该大于0(因为A都是从1开始,Z当然更大)。加入if后,q减1得26,num加回一个26。这样ret += ‘Z’,循环结束。返回ret = ret + 'Z'。

当然,我知道我想复杂了。最简单的方法如下(引自http://blog.csdn.net/doc_sgl/article/details/42246071):

class Solution {
public:
    string convertToTitle(int n) {
        string res = "";
		while(n)
		{
			res = (char)('A' + (n-1)%26) + res;
			n = (n-1) / 26;
		}
		return res;
    }
};




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值