問題描述
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
Explanation: 342 + 465 = 807.
問題分析
1. 思路
本題考察鏈表的操作,利用鏈表從最低位開始逐位求和,并考慮進位進行求解桑腮。
342+456=807的鏈表結(jié)構(gòu)可視化
2. 算法
本題的題目描述和筆算時的方法類似洽损,從最低位開始求和吴攒,也就是鏈表l1和l2的表頭张抄,由于數(shù)字范圍為0~9,需要考慮進位的問題洼怔,且進位只可能是0和1署惯。此外,需要考慮以下特殊情況:
特殊情況 | 解釋 |
---|---|
l1=[0,1], l2=[0,1,2] | 一個列表比另一個列表長 |
l1=[], l2=[0,1] | 列表為空列表 |
l1=[9,9], l2=[1] | sum在最后有一個額外的進位镣隶,這很容易被忽略 |
由以上分析可以得到問題的偽代碼如下:
- 將當前節(jié)點初始化為返回列表的虛擬表頭(dummy)
- 將進位(carry)初始化為0
- 將p和q分別初始化為l1和l2的表頭
? 設(shè)x為節(jié)點p的值极谊。若p抵達l1的表尾,則為0
? 設(shè)y為節(jié)點q的值安岂。若q抵達l1的表尾轻猖,則為0
? 設(shè)sum = x + y + carry
? 更新carry = sum // 10
? 創(chuàng)建一個新節(jié)點,其值為sum%10域那,并將其鏈到當前節(jié)點指向的下一個節(jié)點
? 更新節(jié)點到下一個節(jié)點蜕依,更新p值和q值- 檢查若carry=1,則在返回列表添加一個值為1的新節(jié)點
- 返回虛擬表頭的指向的下一個節(jié)點
注:在這里琉雳,我們采用dummy head的辦法來簡化代碼。如果不設(shè)置dummy head友瘤,我們就需要編寫額外的條件語句來初始化鏈表頭部的值翠肘。
3. 語法細節(jié)
- 定義節(jié)點。使用:類+構(gòu)造方法辫秧,構(gòu)造方法的參數(shù)要有節(jié)點的數(shù)值大小束倍、對下一個節(jié)點的指針。
- 若 l1 表示一個鏈表盟戏,則實質(zhì)上 l1 表示頭節(jié)點的指針绪妹。
4. 復(fù)雜度分析
- 時間復(fù)雜度:O(max(m,n)). 設(shè)m和n分別代表l1和l2的長度,本文所用算法迭代的次數(shù)最多為m和n中的最大值柿究。
- 空間復(fù)雜度:O(max(m,n)). 新鏈表的長度最大為max(m,n)+1邮旷。
Python代碼
# 代碼實現(xiàn)
class ListNode: # 定義節(jié)點,使用:類+構(gòu)造方法
def __init__(self, x):
self.val = x
self.next = None
def AddTwoNumbers(self, l1, l2):
dummy = ListNode(0) # 將當前節(jié)點初始化為返回列表的虛擬表頭(dummy)
carry = 0 # 將進位(carry)初始化為0
p = l1; q = l2; curr = dummy # 將p和q分別初始化為l1和l2的表頭
while(p != None or q != None):
x = p.val if (p != None) else 0 # 設(shè)x為節(jié)點p的值蝇摸。若p抵達l1的表尾婶肩,則為0
y = q.val if (q != None) else 0 # 設(shè)y為節(jié)點q的值。若q抵達l1的表尾貌夕,則為0
sum = x + y + carry # 設(shè)sum = x + y + carry
carry = sum // 10 # 更新carry = sum // 10
curr.next = ListNode(sum % 10) # 創(chuàng)建一個新節(jié)點律歼,其值為sum%10,并將其鏈到當前節(jié)點指向的下一個節(jié)點
curr = curr.next # 更新節(jié)點到下一個節(jié)點
if (p != None): p = p.next # 更新p值
if (q != None): q = q.next # 更新q值
if carry==1 : curr.next = ListNode(1) # 檢查若carry=1啡专,則在返回列表添加一個值為1的新節(jié)點
return dummy.next # 返回虛擬表頭的指向的下一個節(jié)點
# 實例測試
l1_1 = ListNode(2) # 定義鏈表l1: 2 -> 4 -> 3
l1_2 = ListNode(4)
l1_3 = ListNode(3)
l1_1.next = l1_2
l1_2.next = l1_3
l2_1 = ListNode(5) # 定義鏈表l2: 5 -> 6 -> 4
l2_2 = ListNode(6)
l2_3 = ListNode(4)
l2_1.next = l2_2
l2_2.next = l2_3
l3_1 = AddTwoNumbers(ListNode,l1_1,l2_1) # 返回結(jié)果l3: 7 -> 0 -> 8
while l3_1 != None:
print(l3_1.val)
l3_1 = l3_1.next
參考文獻
[1] https://leetcode.com/articles/add-two-numbers/
[2] http://www.reibang.com/p/b98287066140