Java中数组自定义排序与优先级队列笔记

今天在力扣每日一题中又遇到了需要取出数组前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个元素,这种代码编写比较考验基本功。
posted @ 2020-11-09 15:47  浮尘2333  阅读(920)  评论(0编辑  收藏  举报