leetcode973 - 最接近原点的 K 个点(已完善,三种方式解决)

leetcode973 - 最接近原点的 K 个点(sort函数、优先队列、自己手写快排)

介绍

标签:堆、排序、分治算法
建议使用分治算法来解决

leetcode973 - 最接近原点的 K 个点
难度 中等

最接近原点的 K 个点
https://leetcode-cn.com/problems/k-closest-points-to-origin/

题目:

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。


示例 1:

输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释:
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。

示例 2:

输入:points = [[3,3],[5,-1],[-2,4]], K = 2
输出:[[3,3],[-2,4]]
(答案 [[-2,4],[3,3]] 也会被接受。)

提示:

  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000

解题思路

最开始的想法就是调用sort方法来解决,于是就有了前面四个版本的代码

  1. 第一版代码是最普通的重写compare的排序方法,而且没考虑任何优化,所以也就是最慢的
  2. 第二版代码是稍加优化的版本,时间上快了7ms
  3. 第三版代码用到了Comparator.comparingInt与lamda表达式,更加简便也更快
  4. 第四版代码在第三版的基础上再次完善lamda表达式
  5. 第五版也就是最终版,自己手写快排,因为自己写的快排,那么跳出的条件就是只用把K位之前的全部排序完成就好了,可以省下不少时间,详解解释看代码中的注释
  6. 还有用优先队列也就是大根堆的解决的,但是也是调用的内置函数,是后来写的,放最后了。

结果展示

时间效率与空间效率的对比如下:

image.png
后提交的官方那个,先提交那个是我改了的
image.png

代码

第1版

class Solution {
    public int[][] kClosest(int[][] points, int K) {

        Arrays.sort(points, new Comparator<int[]>() {
            public int compare(int[] x, int[] y) {
                int a = x[0] * x[0] + x[1] * x[1];
                int b = y[0] * y[0] + y[1] * y[1];
                return a - b;
            }
        });
        return Arrays.copyOfRange(points, 0, K);

    }
}

第2版

class Solution {
    public int[][] kClosest(int[][] points, int K) {

        Arrays.sort(points, new Comparator<int[]>() {
            public int compare(int[] x, int[] y) {
                return (x[0] * x[0] + x[1] * x[1]) - (y[0] * y[0] + y[1] * y[1]);
            }
        });
        return Arrays.copyOfRange(points, 0, K);
    }
}

第3版

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        //这个方法没学明白,有空看源码
        Arrays.sort(points, Comparator.comparingInt(
            (int[] point) -> (point[0] * point[0] + point[1] * point[1])
        ));
        return Arrays.copyOfRange(points, 0, K);
    }
}

第4版

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        Arrays.sort(points, (a, b) -> ((a[0]*a[0]+a[1]*a[1]) - (b[0]*b[0]+b[1]*b[1])));
        return Arrays.copyOfRange(points, 0, K);
    }
}

第5版

//手写快排
class Solution {
    public int[][] kClosest(int[][] points, int K) {
        int len = points.length;
        //初始化左右两端
        int left = 0;
        int right = points.length - 1;
        int index = - 1;

        //只有当index在K-1位的时候,才说明把前K个点排好序了
        while (index != K - 1) {
            index = partition(points, left, right);
            if (index < K - 1) {
                left = index + 1;
            } else if (index > K - 1) {
                right = index - 1;
            }
        }

        //返回数组中0-k的点
        return Arrays.copyOfRange(points, 0, K);
    }

    /*
        对从left到right排序,仅确保在j之前的距离都比j小
    */
    private int partition(int[][] points, int left, int right) {
        int j = left;
        //取最后一个作为标识长度
        int tmp = getDis(points[right][0], points[right][1]);
        for (int i = left; i < right; ++i) {
            //把所有比tmp放到前面去
            if (getDis(points[i][0], points[i][1]) <= tmp) {
                swap(points, j++, i);
            }
        }
        swap(points, j, right);
        return j;
    }

    /*
        交换元素
    */
    private void swap(int[][] points, int a, int b) {
        int[] t = points[a];
        points[a] = points[b];
        points[b] = t;
    }

    /*
        求距离    
    */
    public int getDis(int x, int y) {
        return x * x + y * y;
    }
}

第6版

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
            public int compare(int[] array1, int[] array2) {
                return array1[0] - array2[0];
            }
        });
        //直接全部进去队列,官方那个还要在后面再次遍历,反而慢些
        for (int i = 0; i < points.length; i++) {
            pq.offer(new int[]{points[i][0] * points[i][0] + points[i][1] * points[i][1], i});
        }
        int[][] ans = new int[K][2];
        for (int i = 0; i < K; ++i) {
            ans[i] = points[pq.poll()[1]];
        }
        return ans;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值