ARTS Week 25
Algorithm
本週的 LeetCode 題目為 371. 兩整數之和
給你兩個整數 a
和 b
,不使用 運算子 +
和 -
,計算並返回兩整數之和。
輸入: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 的英文文章為:編寫程式碼註釋的最佳實踐
多的程式碼註釋不代表其質量有所保證,好的註釋應可以幫助其他人更容易地去理解程式碼,下面是作者提出的一些如何保證程式碼質量的建議:
- 註釋不應與程式碼重複。
不好的示例
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
- 好的註釋不能成為不清晰程式碼的藉口。
不好的示例,變數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;
}
-
如果不能寫清楚的註釋,可能是程式碼有問題。Unix 原始碼中最臭名昭著的註釋是“You are not expected to understand this(你不應該理解這個)”,不幸的是,寫下這些註釋的丹尼斯里奇,他自己也並不完全理解程式碼,後來不得不重寫程式碼。
-
註釋應該消除混亂,而不是引起混亂。如果你的程式碼註釋會引起歧義,請將其刪除。
-
在註釋中解釋單一的程式碼。
不好的示例,程式碼中不應該去解釋大家都能理解的程式碼,除非是在給新手編寫教程。
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;
}
- 提供複製程式碼的原始來源的連結。下面是一個好的示例:
/** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
- 在最有幫助的地方包含指向外部參考的連結。有時候,也可以給出手冊的連結:
// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");
- 修復錯誤時添加註釋。下面是一個好的示例:
// 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) { .. }
- 使用註釋來標記不完整的實現。下面是一個示例:
// 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 系列多,可見平臺和大家更喜歡有具體某一點的教程,未來要更多的創造此型別的文章。