ARTS是什么?
Algorithm:每周至少做一个leetcode的算法题;
Review:阅读并点评至少一篇英文技术文章;
Tip:学习至少一个技术技巧;
Share:分享一篇有观点和思考的技术文章。
Algorithm
LeetCode 4. Median of Two Sorted Arrays
题目解析:
题意是给两个排好序的数组,让你求出这两个数组中所有元素按从小到大排列,排在中间的元素,时间复杂度也是有要求的,O(log(m + n)),m 和 n 分别是这两个数组的长度。这是一道非常经典的题,主要是考察分治的思想。如果分治理解并掌握了,对于这道题来说,难点主要在于边界条件怎么取,还有就是如何对两个数组进行分治,快速排序应该是最常见的应用分治的一个例子,在快速排序中,我们通过一个阈值(数组当中的一个元素)将数组分成两个区间,前一个部分都小于等于这个阈值,后一个部分都大于等于这个阈值,然后我们递归这前后两个区间,让这两个区间再去划分...。但是看到这道题,更多的是一个筛选的过程,我们不断地缩小范围,直到最后找到我们想要的值,因此,与快速排序不同的是,这里我们只需要递归那个我们觉得解会存在的区间,这个思想其实也可以理解为二分查找,准确点说,是基于两个数组的二分查找。所以,我们只需要知道怎么缩小范围即可,题目已经告诉我们,两个数组都是排好序的,如果是单个数组的二分查找我们通常会取数组的中间值,这里也可以这样试试,对两个数组都取到数组中间的元素,这样,我们把两个数组划分成了 4 个部分,下一步操作我们要在这 4 个部分中做取舍,重点是怎么取舍?首先一点是,我们可以比较两个数组的中间的元素,然后依据要取到的元素序号来做舍弃,举个例子:
a = [1,2,3,4,5,6,9]
b = [2,4,5,6,7,8,9]
复制代码
假如我们要选择第 5 个数,我们发现两个数组的前两个部分的元素个数加起来已经超过了 5,我们可以将 b 的后半部分舍弃,也就是 [6,7,8,9]
,注意 a 的不能舍弃,有一种情况是 a 中的所有元素都比 b 中任意元素小,这样 a 的后半部分有可能会存在我们要找的数,那你可能会问为什么 b 的后半部分可以舍,其实很好解释,就是 b 的中间元素比 a 的前半部分大,所以 b 的后半部分的数都比 a 和 b 前半部分的数大,要找的解肯定不在 b 的后半部分,因此可以舍。如果说选择的数超过的两个数组前两部分的元素总数,我们可以舍弃 a 数组的前半部分,即 [1,2,3,4]
,其实原理同上,这里就不再赘述。
另外一个难点是边界条件的选择,我会在代码中写出
参考代码:
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 找出两个数组的中位数的序号
// + 1 的目的是对于奇数来说的,
// 比如说两个数组长度和为 7,排在第 4 的数才是我们要找的
// 这样,这个问题可以变成 “找两个数组中第 k 小的数”
int k = (nums1.length + nums2.length + 1) / 2;
// 如果两个数组长度和是偶数的话,说明中位数有两个,我们需要都找到取平均值
if ((nums1.length + nums2.length) % 2 == 0) {
return (helper(nums1, nums2, 0, nums1.length - 1, 0, nums2.length - 1, k)
+ helper(nums1, nums2, 0, nums1.length - 1, 0, nums2.length - 1, k + 1)
) / 2.0;
}
// 如果是奇数,求解一次就行
return helper(nums1, nums2, 0, nums1.length - 1, 0, nums2.length - 1, k);
}
private double helper(int[] nums1,
int[] nums2,
int start1,
int end1,
int start2,
int end2,
int k) {
if (end1 < start1) {
return nums2[start2 + k - 1];
}
if (end2 < start2) {
return nums1[start1 + k - 1];
}
// 分别求的两个数组区间的中间的 index
// 其实 (start + end) / 2 就可以求得,但是这里写成这样可以防止 start + end 结果越界
int mid1 = start1 + (end1 - start1) / 2;
int mid2 = start2 + (end2 - start2) / 2;
// 先比较两个数组中间元素的大小
if (nums1[mid1] <= nums2[mid2]) {
// k 比较大,k 超过了两个数组区间的前面的部分
// mid1 - start1 和 mid2 - start2 表示的是区间前面部分的元素个数(不包含 mid)
// 这里,我们 (mid1 - start1) + (mid2 - start2) + 1 表示区间 nums1[start1, mid1] 和 nums2[start2, mid2-1] 的元素个数
// 这样做,我们可以舍去 nums1[start1, mid1], 下一个考虑区间就是nums1[mid1 + 1, end1] 和 nums2[start2, end2]
// 可以防止 start1 == mid1 时的无限递归的情况
if ((mid1 - start1) + (mid2 - start2) + 1 < k) {
return helper(nums1, nums2, mid1 + 1, end1, start2, end2, k - ((mid1 - start1) + 1));
}
// k 比较小,和 k 比较大的时候类似,考虑舍去另外一个数组的后半部分
// 边界条件的分析和之前类似
return helper(nums1, nums2, start1, end1, start2, mid2 - 1, k);
}
// nums1[mid1] > nums2[mid2] 的情况,同上
if ((mid1 - start1) + (mid2 - start2) + 1 < k) {
return helper(nums1, nums2, start1, end1, mid2 + 1, end2, k - ((mid2 - start2) + 1));
}
return helper(nums1, nums2, start1, mid1 - 1, start2, end2, k);
}
复制代码
Review
Why Keeping a Daily Journal Could Change Your Life
Minimalist Journaling: A Fun and Effective Tool for Tremendous Habit Change
How To Start A Daily Journaling Habit (And What To Write About)
三篇关于如何日记的文章,我觉得都挺值得一读。第一篇文章主要指出了记日记有哪些好处,第二和第三篇文章给出了记日记的一些方式和方法,其中第二篇文章给出了一个非常有趣的记日记的方式,就是画小方格,形象生动而且记录起来并不会耗费太多的时间,并且记录完后,一眼望过去可以重新回顾之前的内容。
总的说来,记录日记有哪些好处呢,看完文章,我总结了一下:
- 对自己会更加地了解,你把自己每天的所思、所想,所感,甚至担忧和焦虑的事情都给记录下来,你会对自己目前的状态,以及自己想要获得的东西都有个清楚地认识,这就能够让你知己。
- 给自己足够的反馈,让自己不断调整自己的状态,日记中记录一天当中做了什么事情,如果和自己之前相比,没有进展,你可以尝试着去调整,换不同的方法,或者是尝试不同的路径,总之就是要更好地提升自己,有了每天的记录,我们可以通过对比去发现自己目前的不足,及时调整。
- 让自己更放松,心情更舒畅,把自己烦恼的事情记录下来,认真地去思考这个事情是不是没有办法了,你会发现,一天下来,我们都在输入,看微信,刷微博,听课,开会。。。,我们很难得静下心来写点什么。通过思想的输出,能够让你缓解一下压力,把那些我们认为是压力但是其实没什么大不了的事情给写下来,你会发现你的视野会更加的开阔,眼里面的不再是眼前的一亩三分地。
很多人说记日记很烦,很浪费时间,短期来看的确如此,但是我相信每个人每天即使再忙,一天里抽出个半个小时到一个小时的时间还是没有任何问题的。我已经坚持写日记快一年的时间了,感觉自己的日记都是在记录日常发生的事情,中间我也试着改变记录的方式,但是看了这些文章后,我发现还是有很多不足的地方,首先是我记录后并没有回过头去看,另外就是记录的东西没有重点,还有就是当前记录的东西,如果以后需要借鉴,那么找起来会比较地吃力,因此,我需要在日记的格式和内容上下功夫,争取能够让自己更好地成长。
如果你和我一样,已经开始记日记,那么你可以看看第三篇文章中提到的几个记录的意见:
- 记录每天的活动,首先这里不是所有的活动都要记录,记录那些你觉得有意义的,特别是对以后有借鉴意义的东西。你可以记录你学了什么,有什么样的想法,在什么情况下,你感觉很充实,很快乐,以及什么情况下,你对一个问题有了创造性的构思,认真记录这样的场景,等到以后你失落,迷茫,缺乏创作力的时候再回过头去看,看能不能创建之前的场景,相信或多或少会对你有帮助
- 记录此时此刻,你特别担忧的事情,记录让你担忧的事情,努力去思考解决方法,能由自己决定的事情尝试着去改善,不能由自己决定的事情,那就把自己该做的事情做好,尽人事,听天命。
- 写下你的决定,决定可以是生活、学习中的小决定,比如目前这个项目选择哪个框架,要不要花时间看一本别人推荐过的书,等等。思考每个决定的利与弊,以及自己需要面对的问题,有时去深度思考一个问题,往往你会更加欣赏自己当时做的决定。
Tip
这次学习,应该是复习 SQL 语句的时候,重新认识了 HAVING 这个东西,HAVING 的功能其实等同于 WHERE,但是 HAVING 是用于分组中的数据,也就是用于 GROUP BY 之后,这个是 SQL 的聚类的一种方式,其实就是将多条数据合成一条数据,在数据分析中非常常用。
Share
这周学习了下 React 的基础知识,总结一下