细节决定成败。一个小细节可以让代码的性能大幅提升。
最近和朋友一起研究分治算法,看过《算法导论》后觉得,纸上得来终觉浅,绝知此事要躬行啊!遂去 LeetCode 上 Divide and Conquer 这个 Topic 下,做了这道题 973. K Closest Points to Origin。
本文分享作者在做题时发现的优秀代码细节,希望和大家一起吸取营养并体会其中乐趣。
阅读前建议大家先自己做一下该题,至少思考一下,然后再往下阅读,这样更容易体会到这个细节的优雅。
一、题目
973. K Closest Points to Origin
1 | We have a list of points on the plane. Find the K closest points to the origin (0, 0). |
二、代码
题目大意就是让找出距离原点最近的前K个点。并且无需关心结果的顺序。
闲言少叙,直接上改进前的代码:
1 |
|
用时16ms, 反复试了几次也都是10+ms,看到 LeetCode 记录用时最短的方案是 3ms,把这个3ms的方案提交一下,现在用时4ms,大概看了一下,他也是用快速排序,和我的代码几乎一样,但是我的为什么这么慢?
三、找差距,变优秀
差距主要在 quickSort 方法,他的写法类似下面,加了一些判断,去掉了一些不必要的排序,因为题目说 “You may return the answer in any order”, 所以只需找到前K个最小的即可,无需保证前K个按照从小到大的顺序。
1 |
|
改成这样后用时也是4ms. 我对这段代码的理解:
经过一趟快排后,枢轴(支点)的左侧都小于等于它,右侧都大于等于它。
(1)如果枢轴的下标等于K, 则说明枢轴左侧的K个点即是前K个距原点距离最小的点,返回即可;
(2)如果枢轴的下标大于K, 则要想满足(1),只需将 low 至 pivot - 1 继续进行快速排序;
(3)如果枢轴的下标小于K, 则要想满足(1),只需将 pivot + 1 至 high 继续进行快速排序。
由此可见思路上的差异,我之前的思路是利用快速排序进行从小到大排序,然后取前K个,而这种做法是找恰当的枢轴,枢轴左侧的点即是要找的点,省去很多无用功,将快速排序用的恰到好处。
四、总结
解决问题时,要注意题目中的条件,巧用适当的算法。找到与优秀的差距,变成优秀。