一个没有'0'的计数
引言
一直以来,我都对'0'这个数字感到习以为常,'0'不就是代表没有嘛,但当我遇到了下面这个编程题目时,我对'0'的意义有了新的认识,'0'的引进,绝对称得上是计数方式的一次伟大的前进。
题目
给定一个正整数,返回它在 Excel 表中相对应的列名称。
例如,
1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 -> AB ...
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/excel-sheet-column-title
乍一看,这个题目应该是一个十进制与26进制的转换的问题,但细细想来,这个题目用常规的转换方法是无法实现的,因为A~Z中是没有对应'0'的这个值的,所以我们无法用'A0'来简单地代表26这个值,而是用'Z'这个字母来表示26,这个差异导致我们使用传统的除26取余的方法来构建答案会出错,以下是我想出的两种方法。
Solution1:不断自增
既然知道了列的不断增加的法则,那么我们可以用一个循环来实现我们的求值
def inc(val):
carry = True
for i in range(len(val)-1,-1,-1):
if carry:
val[i] = chr(ord(val[i])+1)
if val[i] > 'Z':
carry = True
val[i] = 'A'
else:
carry = False
if carry:
val.insert(0,'A')
def f(n):
val = []
for i in range(n):
inc(val)
return "".join(val)
Solution2:采用除法
首先我们来分析分析一下这个题目求的究竟是什么样一个结果,因为A~Z分别表示的是1~26这26个值,所以我们实际上是要把一个数n转换成如下的形式
其中
Caution:
当我们计算a0的时候,不能够直接用n模26,因为a0的最大值可以是26,所以我们应当多讨论一个特殊情况,即n mod 26 = 0 的情况,这时候a0是可以取Z的。
我们再看n除以26(向下取整)的情况,因为我们的a0是可以取到26的,所以这时候要分两种情况讨论
case1: a0 ≠ 26
这时候我们可以直接继续除下去而不产生错误
case2: a0=26
这时候我们要先减去残留下来的1,继续往下除才能避免出错
所以我们的代码如下
def int2col(n):
res = ""
while n > 0:
temp = n % 26
if temp != 0:
res = chr(ord('A')+temp-1) + res
n = int(n/26)
else:
res = 'Z' + res
n = int((n-1)/26)
return res
Solution2的改进
我们在求a0的时候可以考虑先将n-1,这时候a0的范围就从1~26变成了0~25,即变成了我们熟悉的26进制中每一位的表示方法,这时候我们只要再用n去模上26,就可以得到a0-1的值,从这里我们可以方便地转换为字母表示,同时n减去1后,我们也避免了一次除法过后末尾还留下一个1的情况。实现的代码如下:
def int2col2(n):
res = ""
while True:
n = n - 1
res = chr(ord('A')+n%26) + res
n = int(n / 26)
if n == 0:
break
return res
结论
通过这个题目,我发现'0'的引入对于计数方式的确是一个伟大的进步,它不仅扩充了“无”的表示,它还方便了我们对于各种进制之间的转换,使得我们的计算更为简单,使得我们的计算机在处理各种事情的时候能够更加方便地运算,这确实是一个不可小看的自然数。