2.兩數相加

題目

給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,并且它們的每個節點只能存儲 一位 數字。

如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。

您可以假設除了數字 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

問題:

使用鏈表的操作不太熟悉,對鏈表的使用掌握的不夠!

學習鏈表知識:

鏈表主要包括兩個方面:

數據域 和 指針域

  1. 單鏈表節點信息包括:
  • 數據域 : 用于存儲數據元素的值

  • 指針域(鏈域): 用于存放下一個節點地址或者指向后面節點的指針

struct Node{
    int val; //數據域
    Node *next; //指針域
}

具體參考鏈接...

參考鏈接:

  1. https://www.cnblogs.com/byonecry/p/4458821.html
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 題目地址:https://leetcode-cn.com/problems/add-two-numbers/ 題目...
    monkey01閱讀 535評論 0 0
  • 2. 兩數相加 給出兩個非空的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照逆序的方式存儲的,并且它們的每...
    liulei_ahu閱讀 288評論 0 2
  • 一、題目原型: 給定兩個非空鏈表來表示兩個非負整數。位數按照逆序方式存儲,它們的每個節點只存儲單個數字。將兩數相加...
    花果山松鼠閱讀 525評論 0 0
  • 給定兩個非空鏈表來表示兩個非負整數。位數按照逆序方式存儲,它們的每個節點只存儲單個數字。將兩數相加返回一個新的鏈表...
    0Xday閱讀 391評論 0 0
  • 昨天,我和學姐出去招新,我們社團屬于文學社團,本就是交流探討文學方面的知識,我們向他們介紹讀書的好處,許多新生...