今天在力扣每日一题中又遇到了需要取出数组前n个元素的题目,第一时间想到使用Arrays的sort排序,应该可以自定义比较器,或者使用大顶堆(优先级队列),但是一下没有写出来,还是去查了下资料,因此在这做个笔记以备无患。
-
Arrays的sort自定义比较器:Arrays.sort(数组,(a,b)->{return a-b(升序)/b-a(降序)});
或者使用匿名类Arrays.sort(数组,new Comparator<>() { public int compare(int[] a,int[]b){return a-b(升序)/b-a(降序)});
最后使用Arrays.copyOfRange(原数组, 起点, 终点)返回原数组的子数组即可。
时间复杂度是nlogn,n为数组元素个数 -
由于自定义比较器实现快排需要对数组里所有元素都进行排序,在这种题目中只需要取满足条件的前k个即可,因此可以使用固定k容量的大顶堆结构进行求解,采用的是PriorityQueue的api接口。
首先定义一个优先级队列,定义其比较策略,这里采用的是逆序,因此堆顶元素为最不符合要求的,每次只要和堆顶元素对比即可。
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] array1, int[] array2) {
return array2[0] - array1[0];
}
});
然后将数组前k项加入队列,完成初始化
for (int i = 0; i < K; ++i)
pq.offer(new int[]{points[i][0] * points[i][0] + points[i][1] * points[i][1], i});
最后后续项依次和堆顶进行比较,如果满足则抛出堆顶,将该项加入,PriorityQueue会按照比较策略重新生成堆顶。
int n = points.length;
for (int i = K; i < n; ++i) {
int dist = points[i][0] * points[i][0] + points[i][1] * points[i][1];
if (dist < pq.peek()[0]) {
pq.poll();
pq.offer(new int[]{dist, i});
}
}
到最后剩下的即为所求的,再进行转换下数据结构,返回即可。时间复杂度是nlogk,k为所需要的元素,logk为每次重新插入元素的复杂度,因此比快排小一些。
- 还有一种优化就是,依据快排的思想,对每次排序后左右的元素个数情况进行判断,从而得到前k个元素,这种代码编写比较考验基本功。