出處:
兩個單鏈表(singly linked list),每乙個節點裡面乙個0-9的數字,輸入就相當於兩個大數了。然後返回這兩個數的和(乙個新list)。這兩個輸入的list長度相等。 要求是:1. 不用遞迴。2. 要求演算法在最好的情況下,只遍歷兩個list一次,最差的情況下兩遍。
這是陳利人同學今天發在待字閨中的面試程式設計題目,看了一下解答,發現要麼需要遍歷鍊錶兩次,要麼需要額外的儲存空間,難道就沒有更優的解法了嗎?想了一下,發現還是有的。
利人同學的分析我就不再複述了,這是傳送門:戳我吧!
順便推薦一下陳利人同學的微博:@陳利人和他的公眾平台:待字閨中。一看這同學的名字就值得關注,利人,你值得擁有。xd
ok,我們把這個問題具體化一下吧:(這裡就不再考慮從低到高存等blabla情況)
兩個單鏈表,每個節點儲存乙個0-9的數字,那麼乙個單鏈表就表示乙個大數。從高位到低位存,即表頭對應的是這個大數的最高位。兩個鍊錶的長度相等,我們要返回乙個新的單鏈表,是這兩個輸入鍊錶代表的數的和。我們不能使用遞迴,不能使用額外的儲存空間,即空間複雜度是o(1)。只遍歷輸入鍊錶一次,輸出鍊錶也是單鏈表(沒有前向指標)。
既然只能遍歷兩個輸入鍊錶一次,那我們就從高位加起唄。在這種限制條件下,這是唯一的出路。然後呢?進製咋整?先加高位,再加低位,低位產生的進製怎麼加到高位去?我們可沒有前向指標哦親。既然沒有前向指標,我們就讓乙個臨時指標指向高位,當低位相加產生進製時,我們就可以操作高位了。讓我們看看圖示:
輸入鍊錶1: 1 2 3
輸入鍊錶2: 1 2 8
輸出鍊錶: 2 4
兩個指標: p q
當指向輸出鍊錶當前結點的指標q發現3+8=11,產生進製,指向高位的p就將結點值加1。注意,兩個0-9的數相加,要麼不進製,要麼進製為1,只有兩種情況。因此,我們不用考慮進製是其它數,這一點很重要,後面會看到的。
這樣就ok了嗎?當然不是,如果你遇上連續進製,怎麼破?請看下面的情況:
輸入鍊錶1: 1 2 3 4 5
輸入鍊錶2: 1 7 6 5 9
顯然,指向高位的指標p總是緊跟著指向當前結點的指標q是不行的,這樣當遇上連續進製時,比p更高位的位也需要改變。既然p不能緊跟著q,我們就不讓它們緊挨著,給它們產生點距離。考慮一下,什麼情況下會產生連續進製?9! 嗯,遇上9的時候。它要連續進製到哪一位?不為9的那一位。因此,指標p要停留在和不為9的那一位上,看圖示:
輸入鍊錶1: 1 2 3 4 5
輸入鍊錶2: 1 7 6 5 9
輸出鍊錶: 2 9 9 9
兩個指標: p q
這回當q發現,需要進製了,只需要把p所指結點加1,然後把p,q間的結點都置0即可。為什麼都置0了呢,因為進製只可能是1,9+1=10,留在該位的自然是0了。
分析完畢,這種方法在任何時候都只需要遍歷輸入鍊錶一次,空間複雜度o(1)。
**如下:
#include using namespace std;struct node;
// version 1
node* addsinglylinkedlist(node* list1, node* list2)
else
}else
// 處理後面的結點
while((q1=q1->next) && (q2=q2->next))
else if(num < 9)
pre = q; // 更新前一結點pre的指標
}// num等於9時,p不用更新
if(highest && ans->data == 0) // 如果最高位沒有因為連續進製而變成1
ans = ans->next;
return ans;
}node* makelinkedlist(int d, int n)
return head;
}// version 2, 在處理最高位上,比version1要簡潔
node* addsinglylinkedlist1(node* list1, node* list2)
else if(num < 9)
pre = q; // 更新前一結點pre的指標
}// num等於9時,p不用更新
if(ans->data > 9)
return ans;
}int main();
int b = ;
node *list1 = makelinkedlist(a, n);
node *list2 = makelinkedlist(b, n);
node *ans = addsinglylinkedlist(list1, list2);
for(; ans; ans=ans->next)
cout<<(int)ans->data;
coutcout<<(int)ans1->data;
return 0;
}
求兩個單鏈表的和
出處 兩個單鏈表 singly linked list 每乙個節點裡面乙個0 9的數字,輸入就相當於兩個大數了。然後返回這兩個數的和 乙個新list 這兩個輸入的list長度相等。要求是 1.不用遞迴。2.要求演算法在最好的情況下,只遍歷兩個list一次,最差的情況下兩遍。這是陳利人同學今天發在待字...
求兩個單鏈表的交點(可能帶環)
先簡單分析 兩個單鏈表相交分如圖幾種情況 實現如下 判斷鍊錶是否帶環,若帶環求入口點 pnode iscirclelist pnode phead pnode pfast phead next next pnode pslow phead next while pfast pslow null pf...
單鏈表操作之合併兩個單鏈表
本篇部落格為合併兩個單鏈表,有序和無序都可以 其中用到單鏈表的尾插和單鏈表的選擇排序 中大部分操作都在單鏈表基本操作詳解中介紹過,這裡就直接上 include include includetypedef int datatype typedef struct linknode linknode,p...