(Python3)數據結構——09.單鏈表之計算兩數之和

前言

  • 有Python基礎
  • 有數據結構單鏈表基礎,不清楚的可以參考前面的博客
https://blog.csdn.net/sf9898/article/details/104946291

問題描述

  • 這是某大廠的面試題,現場寫代碼的那種。
給出兩個非空的鏈表,用來表示兩個非負的整數,他們的位數是按逆序存儲的,
並且每一個節點都只能存儲一個數字。如果將這兩個數相加,則會返回一個新的鏈表
來表示他們的和。可以假設除了數字0之外,這兩個數都不會以0開頭。
  • 輸入輸出這一塊劃重點,這裏的輸入輸出是比較抽象的,大致意思對了就行,不是牛客網那種格式化輸入。
輸入(1 -> 6 -> 4)+ (3 -> 1 -> 2)
輸出 (4 -> 7 -> 6)
原因是  461+213 = 674

分析及實現

part1.分析與定義

  • 題目要求是用的鏈表,那麼首先先定義鏈表類。
  • 關於數據的合法性:一般不會爲難人,給的都會是合法數據,不用判斷負數。也不用糾結要是節點存不是一個數字的情況。輸入的都只能是合法的字符。
  • 關於輸入,怎麼輸入就怎麼存,也就是說輸入也是逆序的。
class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None


class Link(object):
    def __init__(self):
        self.__head = None
  • 接下來再寫幾個可能會用到的函數。比如插入和刪除等。題目中說位數是按照逆序存儲的,那麼假設從尾部插入,第一個數進來1,第二次進來6,第三次進來4,那麼根據這個想法,得到的鏈表從頭到尾是不是164,是不是符合題意?實際上表示的數是461,實現了逆序存儲,因此在插入這一塊應該寫尾部插入。
    def addBack(self, item):
        node = Node(item)
        if self.__head is None:
            self.__head = node
            return
        cur = self.__head
        pre = None
        while cur:
            pre = cur
            cur = cur.next
        pre.next = node
  • 常見的判空和遍歷應該也寫上去有助於檢查驗證。
   def isEmpty(self):
        return self.__head is None
 # 定義一個遍歷函數用來驗證
    def travel(self):
        cur = self.__head
        while cur:
            print(cur.item, end=' ')
            cur = cur.next
        print('')
  • ok ,再考慮下刪除和相加的事。如果直接提取兩個數相加可以嗎?小數字貌似可以,但是大的數字呢?看看自己的計算機是幾位的。一萬個、一千個1也是合法數據,照樣得算,照樣得有結果。因此不能採用提取各個節點的item然後拼起來形成一個數相加的方法。應該回歸到小學數學,回到最初的起點。第一個節點是個位,後面的是十位百位…那麼一個一個刪除提取出來做加法,有進位的話要注意。因此在Link類裏面應該有刪除的方法,而且這個方法還要有返回值(不然怎麼算)。
    def removeFront(self):
        # 返回值是一個節點的item,空節點的話返回0,這個函數要做到刪除,並且有返回值
        cur = self.__head
        if cur:
            self.__head = self.__head.next
            return cur.item
        else:
            return 0
  • 上面代碼的寫法是爲了防止三位數加兩位數的這種類似的情況。
  • “如果將這兩個數相加,則會返回一個新的鏈表來表示他們的和。”從題目的這點要求可以看出,我們需要設置一個函數,接收的參數是兩個鏈表的對象(當然,寫別的好像也行,只要能實現)。返回值是一個新的鏈表,當然,這個鏈表依舊是逆序存儲。
def addTwoNum(l1, l2):
    # 參數是兩個鏈表的對象,只要兩個鏈表都不是空那就可以算,3位加2位的話,第二個數的百位就當做0
    ll = Link()
    addNum = 0  # 進位
    while l1.isEmpty() == False or l2.isEmpty() == False:
        temp = l1.removeFront() + l2.removeFront() + addNum
        addNum = 0
        if temp >= 10:
            # 大於等於10要進位哦
            addNum = 1
            temp = temp - 10
        ll.addBack(temp)  # 存進去
    return ll

part2.完整代碼測試一下

# 給出兩個非空的鏈表,用來表示兩個非負的整數,他們的位數是按逆序存儲的,   --一般給的都會是合法數據,不會爲難人
# --這一點說明從頭到尾應該是164(實際上這個鏈表表示的數是461)  312(213)  476(674)
# 第一次輸入的數是1,之後6,然後4,因此是尾部插入
# 並且每一個節點都只能存儲一個數字。如果將這兩個數相加,則會返回一個新的鏈表  --item只能存一個數
# 來表示他們的和。可以假設除了數字0之外,這兩個數都不會以0開頭。
# 相加怎麼進行?直接取出來加??這樣是不行的,因爲PC的計算範圍是有限的,想想自己的電腦是幾位的機子。
# 一千個1加上一千個1理應是一千個2,這樣的數是合法的。因此應當迴歸到最初的起點,用最原始的小學的數學計算去做。
# 先取出個位數,即開頭,然後十位百位...但是這裏又要注意,萬一兩個數的位數是不一樣的呢?
# 從取數字的角度來講,應該是要取開頭

# 輸入(1 -> 6 -> 4)+ (3 -> 1 -> 2)
# 輸出 (4 -> 7 -> 6)
# 原因是  461+213 = 674


class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None


class Link(object):
    def __init__(self):
        self.__head = None

    def isEmpty(self):
        return self.__head is None

    def addBack(self, item):
        node = Node(item)
        if self.__head is None:
            self.__head = node
            return
        cur = self.__head
        pre = None
        while cur:
            pre = cur
            cur = cur.next
        pre.next = node

    def removeFront(self):
        # 返回值是一個節點的item,空節點的話返回0,這個函數要做到刪除,並且有返回值
        cur = self.__head
        if cur:
            self.__head = self.__head.next
            return cur.item
        else:
            return 0

    # 定義一個遍歷函數用來驗證
    def travel(self):
        cur = self.__head
        while cur:
            print(cur.item, end=' ')
            cur = cur.next
        print('')


def addTwoNum(l1, l2):
    # 參數是兩個鏈表的對象,只要兩個鏈表都不是空那就可以算,3位加2位的話,第二個數的百位就當做0
    ll = Link()
    addNum = 0  # 進位
    while l1.isEmpty() == False or l2.isEmpty() == False:
        temp = l1.removeFront() + l2.removeFront() + addNum
        addNum = 0
        if temp >= 10:
            # 大於等於10要進位哦
            addNum = 1
            temp = temp - 10
        ll.addBack(temp)  # 存進去
    return ll


def main():
    l1 = Link()
    l2 = Link()
    N1 = int(input())  # 這個用來接收用戶的輸入,代表第一個數的位數(第一個鏈表的節點數)
    # 接下來輸入1 6 4(類似這樣子),假設是這樣,那麼N1 = 3,下面循環三次,接收三個輸入,尾插三次
    for i in range(N1):
        l1.addBack(int(input()))
    N2 = int(input())  # 第二個數的位數
    for i in range(N2):
        l2.addBack(int(input()))
    # 寫到這裏可以利用遍歷函數初步驗證添加是否成功、是否逆序存儲
    l1.travel()  # 1 6 4
    l2.travel()  # 3 1 2
    # 希望調用一個函數直接計算出結果並返回一串鏈表
    ll = addTwoNum(l1, l2)
    ll.travel()


if __name__ == '__main__':
    main()

part3.根據代碼中的設置,輸入數據驗證

test1

輸入:
3
1
2
3
2
4
5
輸出:
1 2 3
4 5
5 7 3
  • 輸入的第一個數是N1,是第一個數的位數。接下來三個數是123(表示的是321,因爲鏈表裏面逆序存儲)。之後是2,是N2,是第二個數的位數。接下來兩個數是45,表示54。因此在進行加法之後,321+54 = 375,代碼中ll.travel()的結果應是5 7 3。結果如下。

在這裏插入圖片描述

test2

  • 再驗證下題目的數據
輸入:
3
1
6
4
3
3
1
2
輸出:
1 6 4 
3 1 2 
4 7 6 

在這裏插入圖片描述

test3

  • 爲了驗證進位的情況,再設置了一組測試數據,7 3 1(實際表示137),4 6(實際是64),137+64=201,因此結果輸出應該是1 0 2
輸入:
3
7
3
1
2
4
6
輸出:
7 3 1 
4 6 
1 0 2 

在這裏插入圖片描述

  • 如有問題,還望批評指出
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章