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 系列多,可见平台和大家更喜欢有具体某一点的教程,未来要更多的创造此类型的文章。