1. 程式人生 > 其它 >ARTS Week 25

ARTS Week 25

Algorithm

本週的 LeetCode 題目為 371. 兩整數之和

給你兩個整數 ab,不使用 運算子 +-,計算並返回兩整數之和。

輸入:a = 1, b = 2
輸出:3

根據兩個二進位制位相加的四種情況如下:

0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0 (進位)

在不考慮進位的情況下,無進位加法結果為 a^b;而是否進位取決於 a&b,因此進位的結果為 (a&b)<<1。於是,我們可以將整數a和b的和,拆分為a和b的無進位加法結果與進位結果的和。因為每一次拆分都可以讓需要進位的最低位至少左移一位,又因為a和b可以取到負數。因為因為有符號整數用補碼來表示,所以0和負數也適用以上方法。

class Solution {
    public int getSum(int a, int b) {
        while (b != 0) {
            int carry = (a & b) << 1;
            a = a ^ b;
            b = carry;
        }
        return a;
    }
}

Review

本週 Review 的英文文章為:編寫程式碼註釋的最佳實踐

多的程式碼註釋不代表其質量有所保證,好的註釋應可以幫助其他人更容易地去理解程式碼,下面是作者提出的一些如何保證程式碼質量的建議:

  1. 註釋不應與程式碼重複。

不好的示例

i = i + 1;         // Add one to i

一個更極端的錯誤示例

// create a for loop // <-- comment
for // start for loop
(   // round bracket
    // newline
int // type for declaration
i    // name for declaration
=   // assignment operator for declaration
0   // start value for i
  1. 好的註釋不能成為不清晰程式碼的藉口。

不好的示例,變數n

的意義不明確

private static Node getBestChildNode(Node node) {
    Node n; // best child node candidate
    for (Node node: node.getChildren()) {
        // update n if the current state is better
        if (n == null || utility(node) > utility(n)) {
            n = node;
        }
    }
    return n;
}

好的示例,應該將變數n改名為bestNode,這樣不需要註釋也足以讓他人理解。

private static Node getBestChildNode(Node node) {
    Node bestNode;
    for (Node currentNode: node.getChildren()) {
        if (bestNode == null || utility(currentNode) > utility(bestNode)) {
            bestNode = currentNode;
        }
    }
    return bestNode;
}
  1. 如果不能寫清楚的註釋,可能是程式碼有問題。Unix 原始碼中最臭名昭著的註釋是“You are not expected to understand this(你不應該理解這個)”,不幸的是,寫下這些註釋的丹尼斯里奇,他自己也並不完全理解程式碼,後來不得不重寫程式碼。

  2. 註釋應該消除混亂,而不是引起混亂。如果你的程式碼註釋會引起歧義,請將其刪除。

  3. 在註釋中解釋單一的程式碼。

不好的示例,程式碼中不應該去解釋大家都能理解的程式碼,除非是在給新手編寫教程。

final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
    return null;
}
  1. 提供複製程式碼的原始來源的連結。下面是一個好的示例:
/** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
  1. 在最有幫助的地方包含指向外部參考的連結。有時候,也可以給出手冊的連結:
// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");
  1. 修復錯誤時添加註釋。下面是一個好的示例:
// NOTE: At least in Firefox 2, if the user drags outside of the browser window,
// mouse-move (and even mouse-down) events will not be received until
// the user drags back inside the window. A workaround for this issue
// exists in the implementation for onMouseLeave().
@Override
public void onMouseMove(Widget sender, int x, int y) { .. }
  1. 使用註釋來標記不完整的實現。下面是一個示例:
// TODO(hal): We are making the decimal separator be a period, 
// regardless of the locale of the phone. We need to think about 
// how to allow comma as decimal separator, which will require 
// updating number parsing and other places that transform numbers 
// to strings, such as FormatAsDecimal

事實上,很多程式碼註釋其實都和下圖中展示的一樣:

Tip

clock() 函式和 gettimeofday() 函式的異同:

  • 共同點:二者都可以獲取當前的時間,通過對前後的當前時間的求差值,進而得到某段程式碼的執行時間
  • 不同點:clock()是C語言庫函式,也就意味著在任何系統下都可以使用;而 gettimeofday() 函式僅僅是Linux系統中的函式,因此其僅可以在Linux系統中使用。

Share

釋出了C語言的讀寫CSV的教程三部曲,各個平臺的閱讀資料明顯比 ARTS 系列多,可見平臺和大家更喜歡有具體某一點的教程,未來要更多的創造此型別的文章。