算法設計與分析 第一週
兩數相加
題目描述
選題原因
第一次使用領釦,按照他的題目排列順序,選擇了一道中等難度的題目。由於算法課程還沒有很深入,因此沒有選擇課程相關題目。
題目分析
這道題的難點主要在於使用了鏈表表示數字,這樣做導致三個地方的處理需要十分謹慎:
- 鏈表的鏈接
- 兩數字數位不相等時,較長的數字需要再次加上去
- 兩位數所有位數加完後,是否會產生進位
而由於最高位在鏈表尾端,反而使得運算變得簡單,不需要對齊操作。
解題思路
- 由一首一尾兩個指針指向產生的新數字,每次得出新的一位,就更新尾端,最後返回首指針
- 計算每一位時,得到結果後取十位作爲進位,個位作爲結果位
- 先計算兩個數字的共同位數,計算完成後,再計算較長的數字的剩餘位,計算完成後,計算進位
問題
計算共同位數部分
- 野指針問題
在創建新的數字鏈表過程中,使用了一個指針不停的
new
並指向next
,並且用頭節點(頭節點爲空時)與尾節點(頭節點不爲空時)指向它。
struct ListNode* l3;
int add = 0;
struct ListNode* t1 = l1;
struct ListNode* t2 = l2;
struct ListNode* tail;
struct ListNode* t3;
while (t1 -> next != NULL && t2 -> next != NULL) {
int temp = t1 -> val + t2 -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t1 = t1 -> next;
t2 = t2 -> next;
t3 = t3 -> next;
}
但是在編譯的過程中,卻出現了這樣的錯誤:
reference binding to misaligned address 0x5f5f7472617473 for type 'const int', which requires 4 byte alignment
出現綁定錯誤的問題,當l3 = t3
賦值的時候,無法綁定地址,在查閱資料後,對所有的指針進行了初始化操作,再次編譯,結果正常。
struct ListNode* l3 = NULL;
int add = 0;
struct ListNode* t1 = l1;
struct ListNode* t2 = l2;
struct ListNode* tail = NULL;
struct ListNode* t3 = NULL;
- 共同最高位無法計算
在循環中,判斷的條件爲
t1 -> next != NULL && t2 -> next != NULL
,但是在實際的操作中,共同的最高位時無法計算的,例如:[1,2,3] + [1,2,3]
,在計算到3
時,就已經不在判斷條件範圍之內了,爲了解決這個問題,我在循環結束後,單獨進行了一次相同的運算,確保共同最高位能夠被計算。
//計算共同最高位
{
int temp = t1 -> val + t2 -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t1 = t1 -> next;
t2 = t2 -> next;
t3 = t3 -> next;
}
不等長數字高位部分
- 判斷是否等長
我使用了新的指針指向了較長的那一個數字剩餘部分的最低位,並且以此爲判斷條件,繼續運算:
//計算剩餘位
{
struct ListNode* t = NULL;
if (t1 != NULL) {
t = t1;
}
if (t2 != NULL){
t = t2;
}
while (t -> next != NULL) {
int temp = t -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t = t -> next;
t3 = t3 -> next;
}
在操作中,發現如下報錯:
Line 59: member access within null pointer of type 'struct ListNode'
當兩個數字等長時,則得到的新指針是空的,因此是無法指向下一個next
的,因此,在循環開始之前加上判斷的部分:if (t != NULL)
進位部分
進位部分較爲簡單,沒有什麼問題。
源代碼
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
struct ListNode* l3 = NULL;
int add = 0;
struct ListNode* t1 = l1;
struct ListNode* t2 = l2;
struct ListNode* tail = NULL;
struct ListNode* t3 = NULL;
while (t1 -> next != NULL && t2 -> next != NULL) {
int temp = t1 -> val + t2 -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t1 = t1 -> next;
t2 = t2 -> next;
t3 = t3 -> next;
}
//計算共同最高位
{
int temp = t1 -> val + t2 -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t1 = t1 -> next;
t2 = t2 -> next;
t3 = t3 -> next;
}
//計算剩餘位
{
struct ListNode* t = NULL;
if (t1 != NULL) {
t = t1;
}
if (t2 != NULL){
t = t2;
}
if (t != NULL) {
while (t -> next != NULL) {
int temp = t -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t = t -> next;
t3 = t3 -> next;
}
{
int temp = t -> val + add;
t3 = new struct ListNode(temp % 10);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
add = temp / 10;
t = t -> next;
t3 = t3 -> next;
}
}
}
//計算最高位進位
{
if (add != 0) {
t3 = new struct ListNode(add);
if (l3 == NULL) {
l3 = t3;
tail = t3;
} else {
tail -> next = t3;
tail = tail -> next;
}
}
}
return l3;
}
};