@TOC
刷题计划
计划:
- 时间规划(集中式大量刷题 保持题感 养成刷题习惯)
- 按照类型去刷题(数据类型 算法) 网站页面旁边有筛选功能
- 不能死记硬背 要理解题目套路举一反三(这点很重要!)
- 对于新手来说 看答案是可以的,看完在leetcode上写一遍,然后在idea上自己写一遍,写完再在博客上记笔记。(新手不一定能想出来最优解)
- 用笔记本 ipad学习(Goodnotes)
- 利用网上资源 搜索题解视频(微信公众号labuladong) B站:花花酱 B站:小Q刷题 B站:绵羊教授 Youtube :Back To Back SWE
- 解题文章:剑指Offer系列刷题笔记汇总
时间复杂度
计算时间复杂度的方法:
用常数1代替运行时间中的所有加法常数:T(n)=n²+7n+6 => T(n)=n²+7n+1- 修改后的运行次数函数中,
只保留最高阶项: T(n)=n²+7n+1 => T(n) = n² 去除最高阶项的系数: T(n) = n² => T(n) = n² => O(n²)
TOP K 问题
简述:
- TopK是很常见的一种问题,
是指在N个数的无序序列中找出最大的K个数,而其中的N往往都特别大,对于这种问题,最容易想到的办法当然就是先对其进行排序,然后直接取出最大的K的元素就行了,但是这种方法往往是不可靠的,不仅时间效率低而且空间开销大,排序是对所有数都要进行排序,而实际上,这类问题只关心最大的K个数,并不关心序列是否有序, - 因此,排序实际上是浪费了的很多资源都是没必要的。
三种TopK算法:
类选择排序法①为什么叫类选择排序法呢?因为这种方法很像选择排序,选择排序是抽出序列中的最大或最小值放在一端,这里也类似。算法思路:对目标序列N个数遍历,取出其中最大的数最为Top1;再次遍历剩下的N-1个数,取出其中最大的数为Top2;....再对剩下的N-K+1个数遍历,取出其中最大的数为TopK,这样就可以找到最大的K个数了。 ②时间复杂度方面,要求TopK就需要进行K次遍历,然后取出其中最大的数,因此算法平均时间复杂度为O(N*K); ③空间复杂度方面,可以看到这种方法需要开辟一个辅助空间来对取出过的元素进行标记,因此空间复杂度为O(N),除此之外,还需注意到的是,这种方法有效的前提是提前将所有数读入,这样如果一开始的N较大,那么空间开销是不可忽视的,而且,如果数据是动态的,即是可能会不停的增加新数据,那么就还需要每插入一个新数据就将其与前面取出的TopK做比较,排除K+1个数中最小的,最后剩下的才是TopK。快速排序法①在快速排序中,每一轮排序都会将序列一分为二,左子区间的数都小于基准数,右子区间的数都大于基准数,而快速排序用来解决TopK问题,也是基于此的。N个数经过一轮快速排序后,如果基准数的位置被换到了i,那么区间[0,N-1]就被分为了[0,i-1]和[i+1,N-1],这也就是说,此时有N-1-i个数比基准数大,i个数比基准数小,假设N-1-i=X那么就会有以下几种情况: 1、X=K。这种情况说明比基准数大的有K个,其他的都比基准数小,那么就说明这K个比基准数大的数就是TopK了; 2、X<K。这种情况说明比基准数大的数不到K个,但是这X肯定是属于TopK中的TopX,而剩下的K-X就在[0,i]之间,此时就应当在[0,i]中找到Top(K-X),这就转换为了TopK的子问题,可以选择用递归解决; 3、X>K。这种情况说明比基准数大的数超过了K个,那么就说明TopK必定位于[i+1,N-1]中,此时就应当继续在[i+1,N-1]找TopK,这样又成了TopK的一个子问题,也可以选择用递归解决。 ②这种方法是利用了快速排序中找分割点的方法,每次分割后的数组大小近似为原数组大小的一半,因此这种方法的时间复杂度实际上是O(N)+O(N/2)+O(N/4)+……<O(2N),因此时间复杂度为O(N),时间复杂度虽然低,但是这种方法也需要提前将N个数读入,空间开销是一笔负担,并且对于动态的数据放入也是比较“死板”的。堆排序法①堆排序是通过维护大顶堆或者小顶堆来实现的。堆排序法来解决N个数中的TopK的思路是:先随机取出N个数中的K个数,将这N个数构造为小顶堆,那么堆顶的数肯定就是这K个数中最小的数了,然后再将剩下的N-K个数与堆顶进行比较,如果大于堆顶,那么说明该数有机会成为TopK,就更新堆顶为该数,此时由于小顶堆的性质可能被破坏,就还需要调整堆;否则说明这个数最多只能成为Top K+1 th,因此就不用管它。然后就将下一个数与当前堆顶的数作比较,根据大小关系如上面所述方法进行操作,知道N-K个数都遍历完,此时还在堆中的K个数就是TopK了。 ②根据堆排序的复杂度,不难得出,在该方法中,首先需要对K个元素进行建堆,时间复杂度为O(K);然后对剩下的N-K个数对堆顶进行比较及更新,最好情况下当然是都不需要调整了,那么时间复杂度就只是遍历这N-K个数的O(N-K),这样总体的时间复杂度就是O(N),而在最坏情况下,N-K个数都需要更新堆顶,每次调整堆的时间复杂度为logK,因此此时时间复杂度就是NlogK了,总的时间复杂度就是O(K)+O(NlogK)≈O(NlogK)。空间复杂度是O(1)。值得注意的是,堆排序法提前只需读入K个数据即可,可以实现来一个数据更新一次,能够很好的实现数据动态读入并找出TopK。- Top K 问题的三大排序方法解决方案
TOPK演变:
- TOPK演变就是
找出在N个数的无序序列中找出重复次数最最的K个数。 - 解题步骤: ①先通过Hashmap存储, key为数据,value为它出现的次数。 ②然后用优先级队列,存储类型为Map.Entry,重写比较器类,利用value进行比较。 ③优先级队列中利用小根堆形式,只存储十个. ④接下来遍历其他的,如果比小根堆堆顶的要大,对优先级队列进行remove和add操作. ⑤最终,优先级队列中只会存储下来十个value最大的Entry。
- 解题方法二:
其实TOPK演变和TOP K问题差不多 。区别在于
TOPK演变需要遍历一遍然后放入hashmap中然后根据值排序,只排序前K个,这时又变成TOP K问题。
初级入门思路笔记
简述:
- 对于暴力解法 需要双层for循环 注意 条件设置(
不需要两次都全部遍历) - 对于找某数的题 ,找不到后,
需要抛出异常,而不是返回空。 - 需要嵌套循环时,可以先来一层循环,然后使用Map存,用空间换时间