[LeetCode][C++] 用乾淨的方式寫 #2 Add Two Numbers
這一題很簡單,感覺就是在練習資料結構居多,但是很容易就會寫得很亂...
Function 太多行了
我自己一開始練習就寫出像下面這樣子的 C++ code:
class Solution {
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
ListNode *curNode = new ListNode();
ListNode *head = curNode;
int carry = 0;
while (true) {
const int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry;
carry = sum / 10;
curNode->val = sum % 10;
l1 = l1 ? l1->next : l1;
l2 = l2 ? l2->next : l2;
if (!l1 && !l2 && !carry) {
break;
}
curNode->next = new ListNode();
curNode = curNode->next;
}
delete curNode->next;
curNode->next = nullptr;
return head;
}
};
如果我不跟你說題目是什麼,看到的話會覺得這蝦米?
如果你現在上網搜尋其他解答,會發現大家解答好像都長得差不多,反正就是一個 while 裡面做一大坨事。
仔細分析一下我們會發現為什麼通常我們都會寫出很複雜的 code:
- 我們同時要 traverse 兩個 linked list
- 我們同時要輸出到一個越長越長的 linked list
- 我們同時又要算加法,把 carry 帶到下一位
我們把三件事混在一起,當然程式碼會很複雜。
Clean Code
如果我們把上面說的那三件事切開來處理,變成多個 functions,一個 function 專心做一件事,會不會好看一點呢?
我就改寫了一下,多了 3 個 functions 和 2 個 members 來處理不同件事:
class Solution {
public:
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) {
int carry = 0;
while (l1 || l2 || carry > 0) {
const int sum = getValue(l1) + getValue(l2) + carry;
l1 = next(l1);
l2 = next(l2);
addOutputDigit(sum % 10);
carry = sum / 10;
}
return m_head;
}
int getValue(const ListNode *node) {
return node ? node->val : 0;
}
ListNode *next(ListNode *node) {
return node ? node->next : node;
}
void addOutputDigit(const int digit) {
ListNode *newNode = new ListNode();
if (m_tail) {
m_tail->next = newNode;
m_tail = newNode;
} else {
m_head = newNode;
m_tail = newNode;
}
m_tail->val = digit;
}
ListNode *m_head = nullptr;
ListNode *m_tail = nullptr;
};
我們只專注在 addTwoNumbers function 一下子就知道我們想做什麼事,至於底下小小的 function 在做什麼看那些 function name 也很好懂。
不需要註解,又好維護。
Submission
結語
C/C++ 最討厭碰到的就是 pointers,每次看到 pointers 你就可以準備期待程式遇到各種 crash 和錯誤的結果。
所以如果我們要對 pointers 做操作,寫出好懂好維護的程式碼就變得非常重要了,因為這樣出錯的機率也大大降低。
留言
發佈留言