LeetCode Question 2

Question 2

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8

題目分析

輸入:本題的輸入是兩個(gè)自然數(shù),每個(gè)數(shù)都逆序放在鏈表里,比如例子中的 (2 -> 4 -> 3)實(shí)際上是342。并且默認(rèn)除了0以外,自然數(shù)的不會(huì)以0作為開頭,也就是說342不會(huì)以 (2 -> 4 -> 3 - > 0)的形式存在(即0342)。
處理:函數(shù)作用是將兩個(gè)鏈表中的自然數(shù)相加,同樣除了0以外的數(shù)不以0開頭,比如例子中342+465=807。
輸出:將結(jié)果以鏈表形式輸出,即把結(jié)果807用鏈表 (7 -> 0 -> 8)輸出。

檢驗(yàn)設(shè)置

TDD(Test-driven development) analysis:

1. 最簡單的情形是兩個(gè)數(shù)位數(shù)相同且加和不進(jìn)位:
l1 =  (2 -> 4 -> 3), l2 =  (3 -> 2 -> 5)
>>>  (5 -> 6 -> 8)
2. 同樣加和不進(jìn)位的情形下,使兩個(gè)數(shù)位數(shù)不同:
l1 =  (2 -> 4 -> 3), l2 =  (2 -> 5)
>>> (4 -> 9 -> 3)
3. 位數(shù)相/不同的兩個(gè)數(shù)加和進(jìn)位,但保持結(jié)果的鏈表長度等于輸入兩個(gè)鏈表的最大長度:
l1 =  (2 -> 4 -> 3), l2 =  (3 -> 7 -> 5)
>>> (5 -> 1 -> 9)
4. 位數(shù)相/不同的兩個(gè)數(shù)加和進(jìn)位,且結(jié)果的鏈表長度大于輸入兩個(gè)鏈表的最大長度:
l1 =  (2 -> 4 -> 3), l2 =  (3 -> 7 -> 6)
>>> (5 - > 1 -> 0 -> 1)
5. 特殊情況,兩個(gè)數(shù)都是0:
l1 =  (0), l2 =  (0)
>>> (0)

鏈表的結(jié)構(gòu)要事先定義好,這里與題目給出的class一致,鏈表當(dāng)中的值用val表示,連接用next表示,如下

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

為了方便檢驗(yàn),還需要寫兩個(gè)函數(shù)分別實(shí)現(xiàn)創(chuàng)建鏈表和顯示鏈表的功能。

#根據(jù)輸入的列表創(chuàng)建鏈表,列表與鏈表的順序一致
#l = [2, 4, 3](代表自然數(shù)342)
#>>> (2 - > 4 - > 3)
def createListNode(l):
    head = temp = ListNode(0)
    #先設(shè)置一個(gè)head,像基因編碼一樣找一個(gè)生成器
    for i in l:
        temp.next = ListNode(i)
        #將輸入list中的每個(gè)元素變成一個(gè)鏈表結(jié)構(gòu)
        temp = temp.next
    return head.next
    #返回需要的鏈表,扔掉編碼開始的head
#顯示鏈表
#l = (2 - > 4 - > 3)
#>>> 243
def printListNode(ln):
    while ln:
        print(ln.val, end = '')
        #按照鏈表順序輸出value,同時(shí)不換行
        ln = ln.next
    print('')
    #換行,使得后續(xù)輸出的結(jié)果在新一行出現(xiàn),容易辨認(rèn)

1.直接解法(Python3):

既然是在自然數(shù)加法上復(fù)合了鏈表,直接的解法是單獨(dú)處理鏈表與加和:先把輸入的鏈表轉(zhuǎn)換為自然數(shù),再把加和后的結(jié)果轉(zhuǎn)換為鏈表。

def addTwoNumbers(l1, l2):
    def lnToInt(ln):
    #將鏈表(縮寫為名稱的ln,listnode)轉(zhuǎn)化為整型數(shù)(縮寫為名稱的int)
        num = count = 0
        #num代表轉(zhuǎn)化后的整型數(shù),count代表數(shù)位
        while ln:
            num += ln.val * pow(10, count)
            #把鏈表每個(gè)數(shù)字放到整型數(shù)對應(yīng)的位數(shù)上,所以乘以了10的count次方
            count += 1
            ln = ln.next
        return num

    def intToLn(n):
    #將整型數(shù)轉(zhuǎn)換為鏈表
        head = temp = ListNode(0)
        #先設(shè)置一個(gè)head,像基因編碼一樣找一個(gè)生成器
        if n == 0:
            return head
        #如果整型數(shù)為0,直接返回鏈表(0),這也是head設(shè)置為ListNode(0)的好處
        while n:
            temp.next = ListNode(n % 10)
            #找到余數(shù),也就是鏈表對應(yīng)的1位數(shù)元素
            temp = temp.next
            n = n // 10
            #獲得剩下未轉(zhuǎn)換為鏈表的整型數(shù)
        return head.next
    sum = lnToInt(l1) + lnToInt(l2)
    return intToLn(sum)

時(shí)間復(fù)雜度O(n),空間復(fù)雜度O(n),鏈表與加和分開處理的思考難度低,但是效率被浪費(fèi)在鏈表和自然數(shù)的相互轉(zhuǎn)化中,可以繼續(xù)優(yōu)化,方向是賦予鏈表加和能力。

2.鏈表的加法運(yùn)算:

實(shí)現(xiàn)鏈表加法的核心有兩個(gè):進(jìn)位問題和鏈表長度變化問題。這兩個(gè)問題都是由鏈表表示自然數(shù)的規(guī)定引發(fā)的,規(guī)定中要求每一個(gè)鏈表元素都只能是1位數(shù),如果加和出現(xiàn)兩位數(shù)是在鏈表中間,就是進(jìn)位問題,在鏈表末端就是長度變化問題。解決方案是用一個(gè)變量來記錄進(jìn)位的數(shù)字,比如用carry來記錄,鏈表的元素取加和后結(jié)果的個(gè)位數(shù),比如,5+7=12,這時(shí)鏈表的元素取個(gè)位數(shù)2,carry=1,當(dāng)下一位進(jìn)行計(jì)算的時(shí)候把carry的值加入。

def addTwoNumbersNode(l1, l2):
    head = temp = ListNode(0)
    #先設(shè)置一個(gè)head,像基因編碼一樣找一個(gè)生成器
    carry = 0
    #用來存放加和是兩位數(shù)時(shí)的十位數(shù)
    while l1 or l2 or carry:
    #只有當(dāng)l1和l2是null,且carry是0的時(shí)候才停止生成鏈表
        value1 = l1.val if l1 else 0
        value2 = l2.val if l2 else 0
        sum = value1 + value2 + carry
        temp.next = ListNode(sum % 10)
        #鏈表的元素是加和值的個(gè)位數(shù)
        carry = sum // 10
        #carry的值是加和值的十位數(shù)
        temp = temp.next
        l1 = l1.next if l1 else None
        l2 = l2.next if l2 else None
    return head.next

時(shí)間復(fù)雜度O(n),空間復(fù)雜度O(n),實(shí)現(xiàn)了鏈表和加法的功能組合。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容