一个没有'0'的计数

一个没有'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:采用除法

首先我们来分析分析一下这个题目求的究竟是什么样一个结果,因为AZ分别表示的是126这26个值,所以我们实际上是要把一个数n转换成如下的形式

img

其中

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的范围就从126变成了025,即变成了我们熟悉的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'的引入对于计数方式的确是一个伟大的进步,它不仅扩充了“无”的表示,它还方便了我们对于各种进制之间的转换,使得我们的计算更为简单,使得我们的计算机在处理各种事情的时候能够更加方便地运算,这确实是一个不可小看的自然数。

posted @ 2020-03-13 09:59  ColaHua  阅读(281)  评论(0编辑  收藏  举报