腾讯后台开发面试题最后一道面试题题目以及答案:Python链表+大数计算(大数相加,完整代码在文章最后。)

上次面试之后,因为种种原因,没来得及把最后一道题系统地给大家讲解一下,今天有空,就赶快写博给大家分享,谢谢大家的支持!(完整代码在文章最后。)

上次面试的链接:

2020年毕业生腾讯校园招聘提前批——后台开发——面试经验——分享给大家交流经验。

废话不多说,下面进入正题,题目是:使用python3+链表,做数学的相加(大数相加)。

这个地方请不要和我抬杠,当然,Python可以计算很大的数据,这个谁都知道,现在是来讲解这个算法,不是说Python无法计算那么大的数字,今天的重点是算法,算法,算法!!!

链表之前我也写了个博客,链接在这里:

Pyhon3的链表的实现(包含遍历,读取,删除,头插,尾插)

基于上面的链表的实现,我们可以去直接使用上次的链表的代码,来完成我们的大数相加。

基本思路:

首先我们要了解并且明白一件事情:我们进行加减乘除是先加个位,后加十位,然后百位等等。永远是最低位先相加。而链表中,根据单向链表的特性,永远是距离头节点最近的那一个逻辑下标为0的先读取到,所以在存储数据时,我们应当把个位放在下标为0的位置,十位在下标1的位置,百位下标2,以此类推。

上面的明白以后,我们就可以讨论怎么存储了,在C语言中,一个数据存储大小有限,所以应该读取一个数字的字符串如字符串6874156987516435类似的,然后有两种方案:

第一种:循环读取直到 '\0' 这个字符,即尾部的结束符,然后每读取一个使用头插法,就能保证个位距离头部最近。

第二种:计算字符串长度,从尾部读取,然后使用尾插法。

显而易见,对于C语言来讲,明显是第一种较好,省去了很多不必要的计算。

但是,我们现在使用的是Python,我们可以读取一个非常大的数字,虽然Python可以直接存储很大的数据,但是Python的输入默认是字符串,如果全部直接int()转成整形,在循环取整取余,明显有很大的麻烦,所以我们使用C语言的第一种方式,但是Python有遍历,不需要判断最后一个字符是否是 '\0' ,直接遍历读取:

MyList1 = SingleLinkList()
num = input("输入数据:")
for i in num:
    MyList1.add(int(i))
MyList1.travel()

上图就是那串代码的运行结果(不要在意那个命令行的名字,我在笔试的代码的文件夹里写的这个。)

注意:我们使用了上边引用的另外两篇博客其中之一的链表的代码!!!!!!

现在我们有了这样的一个链表,并且个位在第一位了。

正题开始:

那么重点就是,怎么相加,有这么几种情况:

第一:第一个数据比第二个数据长度短很多,比如(2131, 244132415)两个数。

第二:和第一种情况相反。

第三:有进位或连续进位,比如:9999+9999999这种情况。

先把两个数据输入再说,复制上面的代码两份:

MyList1 = SingleLinkList()
num = input("输入数据1:")
for i in num:
    MyList1.add(int(i))
MyList1.travel()
MyList2 = SingleLinkList()
num = input("输入数据2:")
for i in num:
    MyList2.add(int(i))
MyList2.travel()

现在我们完成了数据的输入,我们知道:计算肯定是一个一个的读取的,并不是所有全部读取,这时候就用到了我们的读取的方法:

    # 上面的省略
    def read_next(self):
        """一次读一个"""
        cur = self.__head  # 用来记录当前的节点
        while cur != None:
            # print(cur.elem, end=' ')
            yield cur.elem
            cur = cur.next
        yield None
    # 下面的省略

调用这个,我们能拿到一个生成器,每次读取一个,使用Python的内建方法 next() 来完成一个数据的读取

MyList1_num = MyList1.read_next()
MyList2_num = MyList2.read_next()
num1 = next(MyList1_num)
num2 = next(MyList2_num)

我们还需要两个数,一个存放进位,另一个存放结果:

C1 = 0  # 代表进位
sum = 0 # 代表两个数字的和

再下一个,需要一个存放结果的链表,需要特别注意的是:存放结果的链表,要把个位放在最后。而我们计算时是先计算的个位,后计算的低位,所以我们还是需要使用头插法。

ResList = SingleLinkList()

接下来我们就可以计算了,由于是所有都要计算,所以必须使用到循环:

while num1 and num2:
    sum = num1 + num2 + C1  # 求和
    C1 = sum // 10
    sum = sum % 10
    ResList.add(sum)  # 存放结果的链表
    num1 = next(MyList1_num)
    num2 = next(MyList2_num)

每次相加,我们都需要把进位加上,然后进位拿到非个位部分,这时候保证我们每次插入的是一个一位的数据,而不是直接插入一个超过一位的。

上面的还不够,还记得我们刚刚列举的三种情况的前两个:即两个数的长短不一样。

所以我们还需要判空:

if num1:
    while num1:
        C1 = (num1+C1) // 10
        num1 = (num1+C1)%10
        ResList.add(num1)
        num1 = next(MyList1_num)
if num2:
    while num2:
        C1 = (num2+C1) // 10
        num2 = (num2+C1)%10
        ResList.add(num2)
        num2 = next(MyList2_num)

因为当数据没有后,生成器会返回空,所以直接判空后,让剩余部分对进位相加,继续取整取余完成剩下的运算。

这样够了吗?上面列举的三种情况的最后一个:9999+999999时,经过上面的过程后,进位上还有一个数据,我们还需要把进位也插入结果链表中,最后读取结果链表,就完成了大数相加:

if C1:
    ResList.add(C1)
ResList.travel() # 遍历结果链表

完整代码如下(其中用得到的用不到的我都已经标注明白了,除去用不到的代码总共不到70行。):

# -*- coding:utf-8 -*-
class SingleNode(object):
    """单链表的节点"""
    def __init__(self, elem):
        self.elem = elem  # 存放数据元素
        self.next = None  # 指向下一个数据元素

class SingleLinkList(object):
    """单链表的类"""
    def __init__(self, node=None):
        self.__head = node
        self.__length = 0  # 存放长度,因为这个程序里用不到,所以不需要也可
    def is_empty(self):  # 可以删除,这个程序用不到
        """链表是否为空"""
        return self.__head == None
    def length(self):  # 可以删除,这个程序用不到
        """链表长度"""
        return self.__length
    def travel(self):  # 这个程序用到了这个
        """遍历整个链表"""
        cur = self.__head  # 用来记录当前的节点
        while cur != None:
            print(cur.elem, end='')
            cur = cur.next
        print()
    def read_next(self):  # 这个程序用到了这个
        """一次读一个"""
        cur = self.__head  # 用来记录当前的节点
        while cur != None:
            # print(cur.elem, end=' ')
            yield cur.elem
            cur = cur.next
        yield None
    def add(self, item):  # 这个程序用到了这个
        """在头部添加元素, 头插法"""
        node = SingleNode(item)
        node.next = self.__head
        self.__head = node
        self.__length += 1

    def append(self, item):  # 可以删除,这个程序用不到
        """在尾部添加元素,尾插法"""
        node = SingleNode(item)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next != None:
                cur = cur.next
            cur.next = node
        self.__length += 1

MyList1 = SingleLinkList()
num = input("输入数据1:")
for i in num:
    MyList1.add(int(i))
MyList1.travel()
MyList2 = SingleLinkList()
num = input("输入数据2:")
for i in num:
    MyList2.add(int(i))
MyList2.travel()

MyList1_num = MyList1.read_next()
MyList2_num = MyList2.read_next()
num1 = next(MyList1_num)
num2 = next(MyList2_num)
ResList = SingleLinkList()
C1 = 0  # 代表进位
sum = 0 # 代表两个数字的和
while num1 and num2:
    sum = num1 + num2 + C1  # 求和
    C1 = sum // 10
    sum = sum % 10
    ResList.add(sum)
    num1 = next(MyList1_num)
    num2 = next(MyList2_num)
if num1:
    while num1:
        C1 = (num1+C1) // 10
        num1 = (num1+C1)%10
        ResList.add(num1)
        num1 = next(MyList1_num)
if num2:
    while num2:
        C1 = (num2+C1) // 10
        num2 = (num2+C1)%10
        ResList.add(num2)
        num2 = next(MyList2_num)
if C1:
    ResList.add(C1)
ResList.travel() # 遍历结果链表

写在最后:

大数计算不难,链表也不难,相信自己,世上无难事,只怕有心人!!!

©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页