0%

ARTS 2020 Week 01

Algorithm

3sum(Meidium)

解法一:三层暴力循环,时间复杂度 O(n3) 以上了,直接 PASS。

解法二:先排序,然后从第一个开始,用 0 减去的值当作剩下两数之和,采用 two-sum 的头尾指针办法来解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public List<List<Integer>> threeSum(int[] num) {
Arrays.sort(num);
List<List<Integer>> res = new LinkedList<>();
for (int i = 0; i < num.length-2; i++) {
//为了保证不加入重复的 list,因为是有序的,所以如果和前一个元素相同,只需要继续后移就可以
if (i == 0 || (i > 0 && num[i] != num[i-1])) {
//两个指针,并且头指针从i + 1开始,防止加入重复的元素
int lo = i+1, hi = num.length-1, sum = 0 - num[i];
while (lo < hi) {
if (num[lo] + num[hi] == sum) {
res.add(Arrays.asList(num[i], num[lo], num[hi]));
//元素相同要后移,防止加入重复的 list
while (lo < hi && num[lo] == num[lo+1]) lo++;
while (lo < hi && num[hi] == num[hi-1]) hi--;
lo++; hi--;
} else if (num[lo] + num[hi] < sum)
lo++;
else
hi--;
}
}
}
return res;
}

Review

Kotlin and Exceptions

文章前面介绍了 Java 异常的一些历史,中间主要在说明 Kotlin 中异常应该怎么使用:

  1. 处理程序逻辑错误,比如传入了负值之类的场景,传到程序上层进行处理
  2. 双重用途 API,不确定是逻辑错误还是可以无需干预的输入错误,例如 string.toInt() 这种 API,在后者的情况可以用如下代码解决,而不应该使用异常:
    1
    val number = string.toIntOrNull() ?: defaultValue
  3. API设计
    仅仅在逻辑错误的地方使用异常,而不要用异常来做函数返回值的变通方法。对于不是逻辑错误的异常,可以通过包装结果来避免在逻辑代码中使用 try/catch。
    对于单个错误的场景,可以通过 null 来返回代表错误。对于多种错误的情况,可以使用 sealed class 和 when 来处理。
  4. 输入/输出
    Kotlin 在输入/输出中默认使用异常。应该在代码中指定一个地方,以统一解决所有网络错误。

异步编程和协程,大多数情况和同步编程的异常处理一致。然而,在高度并发的情况下,可以使用结构化协程并发,所有的异常都在上层进行统一处理。

Tips

时间相关系统函数:

  • System.currentTimeMillis()

    这个是我们日常用的最多的了吧,但不是十分精准,而且可以被网络或者用户校准。因此不太适合用来做时间间隔的统计(感觉比较短的间隔还是可以的),但是它适合用来获取当前日期,时刻等时间点相关的逻辑。

  • SystemClock.upTimeMillis()

    记录了系统启动到当前时刻经过的时间。但是系统深度睡眠(CPU睡眠,黑屏,系统等待唤醒)之中的时间不算在。适合所有的不包括系统睡眠时间的时间间隔统计。

  • SystemClock.elapsedRealtime() & SystemClock.elapsedRealtimeNanos
    与SystemClock.upTimeMillis()类似。它是系统启动到当前时刻经过的时间,包括了系统睡眠经过的时间。在CPU休眠之后,它依然保持增长。所以它适合做更加广泛通用的时间间隔的统计。

参考:Android 中的时间

Share

Android 字体那些事