[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 做操作,寫出好懂好維護的程式碼就變得非常重要了,因為這樣出錯的機率也大大降低。

留言

此網誌的熱門文章

[試算表] 追蹤台股 Google Spreadsheet (未實現損益/已實現損益)

[Side Project] 互動式教學神經網路反向傳播 Interactive Computational Graph

[插件] 在 Chrome 網頁做區分大小寫的搜尋