这是两道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;
}
};