題目
給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,并且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807
解法一(我的思路)
思路:
將兩個鏈表代表的數字給表示出來,再將其求和,將將求和結果按照逆序的鏈表形式輸出即可!
/**
* 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) {
// 先計算出兩個鏈表之間所代表的之和
int sum = 0;
int temp_i=1;
ListNode *temp = l1;
do{
sum += temp->val*temp_i;
temp_i = temp_i*10;
temp = temp->next;
}while(temp!=NULL);
temp = l2;
temp_i = 1;
do{
sum += temp->val*temp_i;
temp_i = temp_i*10;
temp = temp->next;
}while(temp!=NULL);
// 計算完成求和 開始創建新的鏈表 用來存放新的數據
ListNode * p = new ListNode(0);
ListNode * q;// 用來移動新生成的鏈表
q = p;
int num = 0;
num = sum % 10;
sum = sum / 10;
p->val = num;
do{
ListNode *newNode = new ListNode(0); // 創建新的節點
if(sum>0) break;
int num = 0;
num = sum % 10;
sum = sum / 10;
// 給臨時節點賦值
newNode->val = num;
newNode->next = NULL;
q->next = newNode; //將臨時節點賦值給移動的鏈表(指向新的鏈表)
q = newNode; // 此時移動的鏈表需要移動到當前節點上來
}while(sum>0);
return p;
}
};
在執行代碼上計算結果與預期的結果一致,但是提交代碼時,老是提示錯誤? 我開始絕望了。執行代碼的時間4ms,但是提交結果會出現錯誤?
錯誤提示為:
Line 28: Char 29: runtime error: signed integer overflow: 1000000000 * 9 cannot be represented in type 'int' (solution.cpp)
始終沒有找到錯誤的原因? 但是覺得自己的思路是對的! 所以就沒有糾結這個問題,查看評論中網友給的答案?
解法二(自己的思路二)
思路:
由于對于該數據表示的單鏈表而言,其表示的第一個數字代表整數的個位數,其表示的第二位代表整數的十位數,以此類推。。。
同理另外一個數也是這樣表示的,所以當兩個數字相加時,就是個位相加,遇到大于10,進一位即可,即可以在對鏈表遍歷的同時計算出最終的結果。
(需要考慮兩個鏈表不一樣長的問題!)
/**
* 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)
{
ListNode *result = new ListNode(0); //存放結果的鏈表
ListNode *p1 ,*p2; //分別指向兩個相加的鏈表
ListNode *temp ; // 臨時節點 存放臨時數據
temp = result;
p1 = l1 , p2 = l2;
int z = 0; // 用來表示最終相同位數求和有沒有超過10的
while(p1!=NULL || p2!=NULL){ //當兩個指針都為空跳出來(思想差不多 不過后面參考了答案)
// 用這種方式可以避免其判斷 兩個鏈表之間的長度問題 當一個鏈表到頭了,用0表示后面位數
int x = (p1!=NULL) ? p1->val : 0 ;
int y = (p2!=NULL) ? p2->val : 0 ;
if(p1) p1 = p1->next;
if(p2) p2 = p2->next;
int sum = z + x+y;
z = sum /10; // 用來記錄大于10的位數(進一位則會記錄下來)
temp->next = new ListNode( sum % 10 );
temp = temp->next;
}
// 當兩者都已經為空 看最后一位有沒有超過10的值
if(z>0) temp->next = new ListNode(z);
return result->next;
}
};
與答案的思想相同,但好像最后有參考答案怎么寫的,雖然用的是java語言,因為覺得他寫的會比我自己寫的更簡潔一點,但是后面還是盡量少的參考答案吧!!!!
中間有發現出現錯誤是,時間超時,后面檢查發現代碼錯誤!! 所以一般不會出現超時的現象!
結果: 時間 40ms 97.14%. 內存 19.2M 37.42%
解答三 (網友答案1)
使用了遞歸的思想,效率挺高的!
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
return addByBit(l1, l2, 0);
}
ListNode* addByBit(ListNode* l1, ListNode* l2, int carry) {
if (l1 == NULL) l1 = new ListNode(0);
if (l2 == NULL) l2 = new ListNode(0);
ListNode *l = new ListNode((l1->val + l2->val + carry) % 10);
carry = (l1->val + l2->val + carry) / 10;
if(l1->next != NULL || l2->next != NULL || carry == 1) {
l->next = addByBit(l1->next, l2->next, carry);
}
return l;
}
};
時間: 40ms
內存: 19.6M
解答四 (網友答案2)
主要的套路跟我第二個套路是一樣的。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *ans = new ListNode(0), *t1=l1, *t2=l2;
ListNode *anshead=ans;
int carry=0;
while(t1||t2){
if(t1){
carry+= t1->val;
t1 = t1->next;
}
if(t2){
carry+= t2->val;
t2 = t2->next;
}
ans->val = carry%10;
carry /= 10;
if(t1||t2||carry){
ans->next = new ListNode(carry);
ans = ans->next;
}
}
return anshead;
}
};
時間:44ms
內存: 19.2M
問題:
使用鏈表的操作不太熟悉,對鏈表的使用掌握的不夠!
學習鏈表知識:
鏈表主要包括兩個方面:
數據域 和 指針域
- 單鏈表節點信息包括:
數據域 : 用于存儲數據元素的值
指針域(鏈域): 用于存放下一個節點地址或者指向后面節點的指針
struct Node{
int val; //數據域
Node *next; //指針域
}
具體參考鏈接...
參考鏈接: