【LeetCode #2 題解】兩數相加
一、題目
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807
二、笨方法題解(因爲存在數據大小侷限性,所以提交時報錯誤)
剛拿到這個問題,第一想法就是這個笨方法,實測結果小沒問題,但一旦數據很大時,會出現超出內存,
所以提交 leetcode 時,自然報錯。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int get_list_value(struct ListNode * l)
{
unsigned long long sum = 0, temp=1;
struct ListNode *p = l;
while(p != NULL){
sum = sum + p->val * temp;
p = p->next;
if(p!=NULL)
temp *= 10;
}
return sum;
}
struct ListNode* int_to_list(unsigned long long value)
{
struct ListNode *result=NULL, *end_l=NULL, *temp=NULL;
unsigned long long value_t = value;
while(value_t / 10 > 0){
temp = (struct ListNode *)malloc(sizeof(struct ListNode));
temp->val = value_t % 10;
temp->next= NULL;
value_t = value_t / 10;
if(result == NULL){
result = temp;
}else{
end_l->next = temp;
}
end_l =temp;
}
temp = (struct ListNode *)malloc(sizeof(struct ListNode));
temp->val = value_t % 10;
temp->next= NULL;
if(result == NULL){
result = temp;
}else{
end_l->next = temp;
}
end_l = temp;
return result;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
unsigned long long sum = 0;
struct ListNode *result;
sum = get_list_value(l1) + get_list_value(l2);
return int_to_list(sum);
}
2.1 測試結果(小數據時計算正常)
2.2 測試結果(大數據時計算錯誤)
繼續增大數據,將前面的數據從1 改 爲 9,
此時,實際結果就出問題了,並不是正確的answer。
三、正解(無侷限性)
詳細的解題思路,我都寫在註釋裏了,可以根據代碼註釋理解下。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* new_ListNode(int val)
{
struct ListNode *new_l = (struct ListNode *)malloc(sizeof(struct ListNode));
new_l->val = val;
new_l->next = NULL;
return new_l;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode *p_l1=l1, *p_l2=l2;
struct ListNode *result=NULL, *temp_l=NULL, *end_l=NULL, *temp_p=NULL;
int val_t=0, advance_flag=0;
// 開始根據鏈表元素按位相加
// 此時分兩種情況:
// 1. L1 和 L2 鏈表當前節點均不爲空,將兩數據相加保存到result鏈表中,同時判斷是否要進位
while( (NULL != p_l1) && (NULL != p_l2) ){
// 計算時加上進位標誌位
val_t = p_l1->val + p_l2->val + advance_flag;
// 清除進位標誌位
advance_flag = 0;
// 如果計算值大於10 ,說明需要進位,設置進位標誌位
if(val_t >= 10){
advance_flag = 1;
}
// 將當前值保存到新 list 中
val_t = val_t % 10;
temp_l = new_ListNode(val_t); // 新建一個list 節點
if(NULL == result){ // 頭結點
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
// 開始下一節點判斷
p_l1 = p_l1->next;
p_l2 = p_l2->next;
}
// 2. L1 和 L2 中有一項爲NULL時,直接保存到result
if( ( (NULL == p_l1) && (NULL != p_l2) ) || ( (NULL != p_l1) && (NULL == p_l2) ) ){
// 得到非空的 listnode
temp_p = (p_l1 != NULL) ? p_l1 : p_l2;
while(temp_p != NULL){
val_t = temp_p->val + advance_flag;
// 清除進位標誌位
advance_flag = 0;
// 如果計算值大於10 ,說明需要進位,設置進位標誌位
if(val_t >= 10){
advance_flag = 1;
}
// 將當前值保存到新 list 中
val_t = val_t % 10;
temp_l = new_ListNode(val_t); // 新建一個list 節點
if(NULL == result){ // 頭結點
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
// 開始下一節點判斷
temp_p = temp_p->next;
}
}
// 3. 跑到這裏說明是已經判斷到最後一個節點了,此時只需要考慮進位的問題了
if(advance_flag == 1){
temp_l = new_ListNode(advance_flag); // 新建一個list 節點
if(NULL == result){ // 頭結點
result = temp_l;
}else{
end_l->next = temp_l;
}
end_l = temp_l;
}
return result;
}
四、提交結果
通過結果看還不錯,內存最優,但運行時間並非最優,
五、別人的更優答案
從 leetcode 上看到了有更快的 8 ms,思路一樣,但他的代碼寫的更加簡潔
地址:《faster than 98.46% of C》
此處附上,可以學習下
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode *head = NULL;
struct ListNode *curNode = NULL;
//記錄上一個節點的和是否有進位
int addNum = 0;
//每個節點當前位的和
int sum = 0;
while (l1!=NULL || l2!=NULL || addNum==1) {
struct ListNode *node = (struct ListNode *)malloc(sizeof(struct ListNode));
node->val = 0;
node->next = NULL;
if (l1!=NULL&&l2!=NULL) {
//兩個鏈表長度都覆蓋到的節點
sum = l1->val + l2->val;
sum += addNum;
int val = sum%10;
node->val = val;
l1 = l1->next;
l2 = l2->next;
}else if (l1!=NULL) {
sum = l1->val;
sum += addNum;
int val = sum%10;
node->val = val;
l1 = l1->next;
}else if (l2!=NULL) {
sum = l2->val;
sum += addNum;
int val = sum%10;
node->val = val;
l2 = l2->next;
}else {//兩個鏈表都遍歷結束但尾節點相加還有進位
node->val = 1;
addNum = 0;
sum = 0;
}
addNum = sum>=10 ? 1 : 0;
if(head==NULL){
head = node;
}else{
curNode->next = node;
}
curNode = node;
}
return head;
}