Skip to content

Commit 397fc01

Browse files
committed
docs: enhance README for Add-Two-Numbers with UMPIRE solution details and improved clarity on algorithm and edge cases
1 parent 217127d commit 397fc01

1 file changed

Lines changed: 92 additions & 40 deletions

File tree

Lines changed: 92 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,56 @@
11
---
2+
title: UMPIRE 2.Add-Two-Numbers
3+
subtitle: "https://leetcode.com/problems/add-two-numbers/description/"
4+
date: 2024-03-02T15:57:00+08:00
5+
lastmod: 2024-03-02T15:57:00+08:00
6+
draft: false
7+
author: "Kimi.Tsai"
8+
authorLink: "https://kimi0230.github.io/"
9+
description: "UMPIRE Solution for 0002.Add-Two-Numbers"
10+
license: ""
11+
images: []
12+
13+
tags:
14+
- LeetCode
15+
- Go
16+
- Medium
17+
- Add Two Numbers
18+
- Linked List
19+
- Math
20+
- Recursion
21+
- Amazon
22+
- Apple
23+
- Facebook
24+
- Microsoft
25+
- Bloomberg
26+
categories: [LeetCode]
27+
28+
featuredImage: ""
29+
featuredImagePreview: ""
30+
31+
hiddenFromHomePage: false
32+
hiddenFromSearch: false
33+
twemoji: false
34+
lightgallery: true
35+
ruby: true
36+
fraction: true
37+
fontawesome: true
38+
linkToMarkdown: false
39+
rssFullText: false
40+
41+
toc:
42+
enable: true
43+
auto: true
44+
code:
45+
copy: true
46+
maxShownLines: 200
47+
math:
48+
enable: false
49+
share:
50+
enable: true
51+
comment:
52+
enable: true
53+
---
254

355
# Solution - UMPIRE
456

@@ -11,41 +63,41 @@
1163
- 除非是數字 0 本身,否則這兩個數字都不會有前導零。
1264
- 兩個鏈結串列的長度可能不同。
1365
- **澄清與細節**
14-
- 題目保證非空,所以不需處理空指標作為輸入的情況
15-
- 需要處理進位(Carry)。
66+
- 題目保證輸入串列非空,且內容皆為非負整數
67+
- 需要精確處理「進位(Carry)」邏輯,尤其是最後一位產生的進位
1668
- **測試案例定義**
1769
- **Happy Path**:
1870
- $L1: [2, 4, 3]$ (342), $L2: [5, 6, 4]$ (465) $\rightarrow$ 結果: $[7, 0, 8]$ (807)
1971
- **Edge Cases**:
20-
- **長度不同**: $L1: [9, 9, 9, 9, 9, 9, 9]$, $L2: [9, 9, 9, 9] \rightarrow$ 需要處理不同步的結束
21-
- **最後進位**: $L1: [5]$, $L2: [5] \rightarrow$ 結果: $[0, 1]$,最後多出一個節點
22-
- **其中一個為零**: $L1: [0]$, $L2: [7, 3] \rightarrow$ 結果: $[7, 3]$。
72+
- **長度不同**: $L1: [9, 9, 9]$, $L2: [1] \rightarrow$ 結果: $[0, 0, 0, 1]$ (處理不同步結束與連續進位)
73+
- **最後進位**: $L1: [5]$, $L2: [5] \rightarrow$ 結果: $[0, 1]$ (最後迴圈結束後仍有進位)
74+
- **值為零**: $L1: [0]$, $L2: [0] \rightarrow$ 結果: $[0]$。
2375

2476
### M – Match(匹配知識)
2577
- **主要演算法/資料結構**:鏈結串列遍歷(Linked List Traversal)與基礎算術(Elementary Math)。
2678
- **為什麼適合**
27-
- 因為數字已經是逆序儲存,這非常符合我們手寫加法的習慣(從個位數開始加),我們只需要同時遍歷兩個串列即可
79+
- 數字逆序儲存的特性與我們手寫加法「從右往左」的順序完全一致,只需單向遍歷即可
2880
- **為什麼其他解法不理想**
29-
- 若先將鏈結串列轉為大整數(BigInt)再相加後轉回串列,雖然可行,但會消耗額外的空間與轉換時間,且無法處理超過 64 位元整數範圍的情況(若題目沒有明確限制範圍)。直接在鏈結串列上操作是最直觀且有效率的
81+
- 轉換成整數再相加會面臨整數溢位(Integer Overflow)的問題,且轉換過程會產生額外的時間與空間開銷。直接在鏈結串列上逐位計算是最符合題意的最優解
3082

3183
### P – Plan(制定計畫)
3284
- **解題流程**
33-
1. 初始化一個 `dummyHead` 節點來作為結果串列的起始,以及一個指標 `curr` 指向它
34-
2. 初始化 `carry` 為 0
35-
3. 同時遍歷 `l1` `l2`,只要 `l1 != nil` 或 `l2 != nil` 或 `carry != 0` 就繼續迴圈
36-
- 取得 `l1` 的值(若已結束則為 0)。
37-
- 取得 `l2` 的值(若已結束則為 0)。
38-
- 計算 `sum = val1 + val2 + carry`。
39-
- 更新 `carry = sum / 10`。
40-
- 創建新節點其值為 `sum % 10`,掛在 `curr.Next`。
41-
- `curr``l1``l2` 分別移至下一個位置
85+
1. 使用 `dummyHead` 簡化首個節點的處理,並用 `curr` 指標追蹤結果串列的尾部
86+
2. 初始化進位變數 `carry = 0`
87+
3. 遍歷條件:只要 `l1` 沒走完 OR `l2` 沒走完 OR 還有進位 `carry != 0`
88+
- `l1` 取值(若為 nil 則補 0)。
89+
- `l2` 取值(若為 nil 則補 0)。
90+
- `sum = val1 + val2 + carry`
91+
- `carry = sum / 10`
92+
- 建立值為 `sum % 10` 的新節點,接在 `curr.Next`
93+
- 移動 `curr` 以及 `l1` / `l2` 指標
4294
4. 回傳 `dummyHead.Next`
4395
- **資料流與狀態變化**
44-
- 每次疊代都會處理一位數
45-
- `carry` 狀態會在下一次疊代中被累加
96+
- `carry` 狀態跨越每一次疊代傳遞
97+
- 透過 `l1``l2` 的同步移動確保位數對齊
4698
- **預防 Bug**
47-
- 注意迴圈結束條件,必須包含 `carry != 0`,否則最後一位進位會被遺漏(例如 5+5=10)
48-
- 檢查指標是否為 `nil` 才能存取 `Val`。
99+
- 確保 `while` 迴圈結束後,如果 `carry` 仍大於 0,必須補上最後一個節點
100+
- 在存取 `l1.Val` 之前務必檢查 `l1 != nil`
49101

50102
### I – Implement(實際實作,Golang)
51103
```go
@@ -84,43 +136,43 @@ func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
84136

85137
### R – Review(檢查與回顧)
86138
- **Dry Run**:
87-
- 輸入:$L1: [2, 4, 3], L2: [5, 6, 4]$
139+
- 輸入:$L1: [2, 4], L2: [5, 6, 4]$
88140
- 1st: $2+5+0 = 7, carry=0, Result: [7]$
89141
- 2nd: $4+6+0 = 10, carry=1, Result: [7, 0]$
90-
- 3rd: $3+4+1 = 8, carry=0, Result: [7, 0, 8]$
91-
- 結束。回傳 $[7, 0, 8]$
92-
- **關鍵狀態轉移**:`carry` 正確地從十位數轉移到下一位的個位數
93-
- **邊界確認**:如果輸入是 $L1:[9], L2:[1]$,迴圈會跑兩次,第二次處理 `carry=1`,產出 $[0, 1]$,正確
142+
- 3rd: $0+4+1 = 5, carry=0, Result: [7, 0, 5]$
143+
- 回傳 $[7, 0, 5]$,正確($42 + 465 = 507$)
144+
- **關鍵狀態轉移**進位正確地在疊代間傳遞
145+
- **邊界確認**單節點 $5+5$ 會產生兩個節點的結果 $[0, 1]$,邏輯正確
94146

95147
### E – Evaluate(總結與評估)
96-
- **時間複雜度**: $O(\max(M, N))$,其中 $M$ 和 $N$ 分別為兩個串列的長度。我們只需遍歷最長的那一個一次
97-
- **空間複雜度**: $O(\max(M, N))$,回傳的結果串列長度最多為 $\max(M, N) + 1$。若不計入回傳空間,則為 $O(1)$。
98-
- **權衡與優化**:這個方法已經是時間與空間的最優解。唯一的優化可能是原位(In-place)修改,但因為相加後長度可能增加,且通常不建議修改輸入參數,所以使用新串列是標準做法
148+
- **時間複雜度**: $O(\max(M, N))$,其中 $M, N$ 為兩串列長度。我們只遍歷了最長串列一次
149+
- **空間複雜度**: $O(\max(M, N))$,用於儲存結果串列(若不計入回傳值則為 $O(1)$
150+
- **權衡與優化**本解法已達最優。若要極致優化空間,可考慮原位修改(In-place),但會破壞輸入資料且程式碼複雜度會大幅提升,通常不建議這樣做
99151

100152
---
101153

102154
## Output 2: 面試官口語回答腳本(精簡可直接說)
103155

104156
### 1️⃣ 開場:題目理解
105-
這題要求我們將兩個以逆序鏈結串列表示的整數相加,並回傳同樣是逆序的結果串列。核心在於如何處理兩串列長度不等的情況,以及數值相加後的進位處理
157+
這題要求我們處理兩個逆序排列的鏈結串列,將它們代表的整數相加。主要的挑戰在於處理進位以及當兩個串列長度不一致時的對齊問題
106158

107159
### 2️⃣ 解法選擇說明
108-
我會採用**同時遍歷(Simultaneous Traversal)**的方法。因為題目給的數字已經是從個位數開始的逆序排列,這正好符合手算加法從右到左的邏輯。這種做法的時間複雜度是線性 $O(\max(M, N))$,是最直觀且高效的解法
160+
我選擇採用**線性遍歷(Simultaneous Traversal)**配合**基礎進位邏輯**。因為串列已經是逆序排列(低位在首),這正好符合我們手算加法的順序,直接一邊走一邊加是最有效率的,時間複雜度是 $O(\max(M, N))$。
109161

110162
### 3️⃣ 解題策略概覽
111-
我會建立一個 Dummy Head 來簡化鏈結串列的操作。接著使用一個 `while` 迴圈同時遍歷兩個串列,並維護一個 `carry` 變數來存儲進位值。在每一次疊代中,我把兩個節點的值與當前的進位相加,取餘數作為新節點的值,取商數作為下一次的進位。這個迴圈會持續運行,直到兩個串列都走完「且」進位值為 0
163+
我會建立一個 **Dummy Head** 來方便管理結果串列的成長。在迴圈中,我會同時檢查兩個指標,只要其中一個還有數字或者還有進位,我就把值加總起來,存入新節點,並把產生的進位傳給下一輪
112164

113165
### 4️⃣ 寫程式時會補充的關鍵說明
114-
* **Dummy Head 的使用**這可以讓我們在建立結果串列時,不需要特別判斷第一個節點是否為空,代碼會更簡潔
115-
* **防呆判斷**在取值時,一定要先檢查指標是否為 `nil`,如果其中一個串列比較短,我們就補 0 進行運算
116-
* **最後進位處理**迴圈的條件必須包含 `carry != 0`確保像是 $99 + 1$ 這種最後產生的進位能被正確補在串列末端
166+
* **Dummy Head 技巧**使用虛擬頭節點可以讓程式碼更簡潔,避免在迴圈內一直判斷 `head` 是否為空的邏輯
167+
* **靈活處理不等長**當其中一個串列結束時,我會將其值視為 $0$,這樣可以用同一套邏輯處理完所有的位數
168+
* **強健的結束條件**我的迴圈條件會包含 `carry != 0`這能自動處理像是 $5+5$ 這種最後多出一位進位的情況
117169

118170
### 5️⃣ 快速 Dry Run 說明
119-
以 $[2, 4, 3]$ 加 $[5, 6, 4]$ 為例:
120-
第一位 $2+5=7$,無進位。
121-
第二位 $4+6=10$, $0$ 進位 $1$。
122-
第三位 $3+4$ 再加上剛才的進位 $1$ 等於 $8$。
123-
最後結果就是 $[7, 0, 8]$。
171+
假設 $L1=[2, 4]$,$L2=[5, 6, 4]$
172+
第一位相加 $2+5=7$,無進位。
173+
第二位相加 $4+6=10$,結果寫 $0$進位 $1$。
174+
最後 $L1$ 走完了,剩 $L2$ 的 $4$ 加上剛才的進位 $1$ 等於 $5$。
175+
最終結果就是 $[7, 0, 5]$。
124176

125177
### 6️⃣ 收尾總結
126-
這套演算法的**時間複雜度是 $O(\max(M, N))$****空間複雜度也是 $O(\max(M, N))$**(用於儲存結果)。這種解法穩定且能處理極大的數值,因為它完全避開了整數溢出的限制
178+
這套演算法在**時間與空間複雜度上都是線性 $O(\max(M, N))$**。它能有效處理任意長度的數字,且不受程式語言整數型態大小的限制

0 commit comments

Comments
 (0)