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. 解法 暴力解法代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { 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; } 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public int [][] kClosest(int [][] points, int K) { 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) { 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 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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; } 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 ; } }