LeetCode 973. K Closest Points to Origin

Problem

LeetCode 973. K Closest Points to Origin

1. 题目简述

给出某二维平面上的一些坐标,例如[1, 2],找出这些坐标中距离原点最近的K个节点。例如:

Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]

Note:

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

2. 算法思路

这道题难倒是不难,思路也很明确,其实主要是考察数据结构的熟悉程度以及API的调用,否则写起来很麻烦。

暴力解法

首先我们需要记录每个节点与原点的距离,然后进行排序,找出前k个,并把这k个的对应的pair找出来。

用最笨的办法的话就是用个map记录一下distance和对应的index之间的关系,然后排序结束以后找出前k的distance,然后再从map中找出index,再进行遍历。这个方法很麻烦,而且耗时长。

使用Arrays.sort方法自定义排序

我们知道Arrays.sort函数可以默认排序数字类型,但是其更广泛的用法其实是自定义排序任意类型,这点和Collections.sort一个道理。

详情见:Java知识点记录——第一项

使用PriorityQueue自定义比较方式

同上,只不过queue也是一种List,可以用Comparator来自定义比较方式从而初始化一个小顶堆。这里有两种方式,多种写法。

分治法

找top k问题的常见套路,写一个helper函数来找一个合适的mid,其实并不需要全局有序,只要部分有序就可以了。

3. 解法

暴力解法代码

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        Map<Integer, List<Integer>> distanceMap = new HashMap();
        List<Integer> distances = new ArrayList();

        for (int i = 0; i < points.length; i++) {
            int distance = points[i][0] * points[i][0] + points[i][1] * points[i][1];
            distances.add(distance);
            if (!distanceMap.containsKey(distance)) {
                distanceMap.put(distance, new ArrayList<Integer>());
            }
            distanceMap.get(distance).add(i);
        }

        Collections.sort(distances);

        int[][] res = new int[K][2];
        int count = 0, index = 0;
        while (count < K) {
            int target = distances.get(index);
            List<Integer> targetIndexes = distanceMap.get(target);
            for (int i = 0; i < targetIndexes.size(); i++) {
                int x = targetIndexes.get(i);
                res[count][0] = points[x][0];
                res[count][1] = points[x][1];
                count++;
            }
            index++;
        }

        return res;
    }
}

使用Arrays.sort()

class Solution {
    // 解法1
    public int[][] kClosest(int[][] points, int K) {
        int[][] res = new int[K][2];
        int index = 0;

        Arrays.sort(points, (point1, point2) -> point1[0] * point1[0] + point1[1] * point1[1] - point2[0] * point2[0] - point2[1] * point2[1]);

        while (index < K) {
            res[index] = points[index];
            index++;
        }

        return res;
    }

    // 解法2
    public int[][] kClosest(int[][] points, int K) {
        Arrays.sort(points, Comparator.comparing(p -> p[0] * p[0] + p[1] * p[1]));
        return Arrays.copyOfRange(points, 0, K);
    }
}

使用PriorityQueu+Comparator

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        // 要大顶堆,所以返回p2 - p1
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>((p1, p2) -> p2[0] * p2[0] + p2[1] * p2[1] - p1[0] * p1[0] - p1[1] * p1[1]);

        for (int[] p : points) {
            queue.offer(p);
            if (queue.size() > K) {
                queue.poll();
            }
        }

        int[][] res = new int[K][2];
        while (K > 0) {
            res[--K] = queue.poll();
        }

        return res;
    }

    public int[][] kClosest(int[][] points, int K) {
        // 要大顶堆,所以返回p2 - p1
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>((p1, p2) -> p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1]);

        queue.addAll(Arrays.asList(points));

        int[][] res = new int[K][2];
        while (K > 0) {
            res[--K] = queue.poll();
        }

        return res;
    }
}

使用分治法找top k


class Solution {
    public int[][] kClosest(int[][] points, int K) {
        int l = 0, r = points.length - 1,

        while (l <= r) {
            int mid = helper(points, l, r);
            if (mid == K) {
                break;
            } else if (mid < K) {
                l = mid + 1;
            } else if (mid > K) {
                r = mid - 1;
            }
        }

        return Arrays.copyOfRange(points, 0, K);
    }

    private int helper(int[][] points, int l, int r) {
        int[] pivot = points[l];
        while (l < r) {
            while (l < r && compare(points[r], pivot)) {
                r--;
            }
            points[l] = points[r];
            while (l < r && compare(pivot, points[l])) {
                l++;
            }
            points[r] = points[l];
        }
        points[l] = pivot;
        return l;
    }

    // p1是否大于p2
    private boolean compare(int[] p1, int[] p2) {
        return (p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1]) >= 0;
    }
}