LeetCode-兩數相加

梨子啊荔枝發表於2024-08-06

前言

這道題將整數加法轉換為在單連結串列上做加法運算,涉及到知識點:

  1. 單連結串列的遍歷
  2. 單連結串列插入新節點

題目描述

給你兩個 非空 的連結串列,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式儲存的,並且每個節點只能儲存 一位 數字。

示例1:

輸入:l1 = [2,4,3], l2 = [5,6,4]
輸出:[7,0,8]
解釋:342 + 465 = 807.

示例2:

輸入:l1 = [0], l2 = [0]
輸出:[0]

示例3:

輸入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
輸出:[8,9,9,9,0,0,0,1]

提示

  • 每個連結串列中的節點數在範圍 [1, 100]

  • 0 <= Node.val <= 9

  • 題目資料保證列表表示的數字不含前導零

題目分析

單連結串列遍歷只能 單向單步:給定一個節點的指標,那麼它只能訪問下一個節點的內容。單連結串列的遍歷時間複雜度唯一: \(\mathcal{O}(n)\)

注意到:由於每個節點只能儲存一位數字,那麼兩個對應位相加的最大值為 \(9 + 9 = 18\) ,因此我們的十進位制 進位 最大隻會為 1

暴力演算法

就像普通的十進位制數加法一樣,每一位相加後對 \(10\) 取餘作為當前位的答案,而對 \(10\) 取商作為進位。遍歷完後還需要判斷是否進位不為 \(0\) ,如果不為 \(0\) ,就還需要增加數字為 \(1\) 的節點。

假設 \(A\) 代表 \(L_1\) 連結串列, \(B\) 代表 \(L_2\) 連結串列, \(C\) 代表 \(L_1\)\(L_2\) 的和 :

\[C = A + B \\ \]

因此給出數學公式:

\[\begin{equation} \begin{aligned} \begin{cases} C_i &= A_i + B_i + t(\text{進位}),\qquad &0\leq i\leq max(A.length , B.length)\\ \\ \\ C_i &= 1, & t = 1 ,\quad i = max(A.length , B.length) + 1 \end{cases} \end{aligned} \end{equation} \]

解題程式碼

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode();
        ListNode* cur = head;
        int t = 0;
        while ( l1 || l2) {
            if ( l1) {
                t += l1->val;
                l1 = l1->next;
            }
            if ( l2) {
                t += l2->val;
                l2 = l2->next;
            }
            ListNode* nnew = new ListNode(t % 10);
            cur->next = nnew;
            t /= 10;
            cur = cur->next;    // 準備下一次的增加新節點
        }
        if ( t ) {
            ListNode* nnew = new ListNode(1);
            cur->next = nnew;
        }
        return head->next;
    }
};

複雜度分析

\[\begin{equation}\begin{aligned} \mathcal{O}(Complex) &= \mathcal{O}(\text{單個節點處理:申請節點,插入節點})\\ &+\mathcal{O}(遍歷) \\ &= \mathcal{O}(k\times n) + \mathcal{O}(n )\\ \end{aligned}\end{equation} \]

最終我們的時間複雜度為 \(\mathcal{O}(n)\)

我們在剛開始刷題的時候,可以先試著自己寫出暴力演算法,然後分析一下時間複雜度,再嘗試其他解題方法。

相關文章