Leetcode973. K Closest Points to Origin

We have a list of points on the plane. Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)

You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:

Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation: 
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].

Example 2:

Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

Note:

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

Approach1. PriorityQueue - maxHeap

When we get this question, we definitely want a data structure to store things as close as possible to us, and so there's gonna sound a little counterintuitive, but I think the way we are going to do, this is we are going to use a max-heap. Okay and so we are gonna use a max-heap and we are gonna make sure that our heap is always of size K or at most K, and so every single time you add something to the heap and it's greater than K, we are just gonna remove the next thing in the heap, and so what that will do is it will take the maximum or the largest or furthest point from the origin, and it's gonna kick it out.

Awesome, so that's how we are gonna do this, we are actually going to create a heap keeping it at most of size K, and we are gonna organize our heap by the largest distance away from the origin. So then once we basically inserted all of our points removing anything from the root of the heap every time, it gets greater than K when our loop terminates, we will basically have the K smallest points or K closest points to the origin.

So, Let's go ahead and do that, we are gonna have a priority queue, and it's going to hold Integer arrays, we are going call this maxHeap equals new Priority queue and we are gonna write a comparator here, we gonna say a comma b meaning two points, and so now this is like where the math kind of comes in but we are basically just calculating the Euclidean distance, so don't worry about this. So now we are going to do is we are just going to throw all of our points in the heap. Next, using for loop, every point in our points, we are going to add it to the heap. now we are gonna check right, so if max-heap.size() is greater than K, then we need to remove something, so we're gonna remove from the heap, we're gonna remove from the root. So we are actually removing the point that is a farthest away right now.

Instead, we can maintain a max-heap with size K. Then for each point, we add it to the heap. Once the size of the heap is greater than K, we are supposed to extract one from the max heap to ensure the size of the heap is always K. Thus, the max heap is always maintained top K smallest elements from the first one to the current one. Once the size of the heap is over its maximum capacity, it will exclude the maximum element in it, since it can not be the proper candidate anymore.

Theoretically, the time complexity is O(NlogK),

The advantage of this solution is it can deal with real-time(online) stream data. It does not have to know the size of the data previously.
The disadvantage of this solution is it is not the most efficient solution.

The shortcode shows as follows:

class Solution {
     public int[][] kClosest(int[][] points, int K) {
          if(points == null || points.length == 0 || K < 1){
              return points;
         }
         PriorityQueue<int []> pq = new PriorityQueue<int []>((a, b) -> getDistanceSquare(b) - getDistanceSquare(a));
         
         for(int[] point : points){
             pq.add(point);
             if(pq.size() > K){
                 pq.poll();
             }
         }
         int [][] res = new int[K][2];
         for(int i = 0; i < K; i++){
             res[i] = pq.poll();
         }
         return res;
     }
     
     private int getDistanceSquare(int [] point){
         return point[0]*point[0] + point[1]*point[1];
     }
}

用maxHeap来维护K shortest distence.
Time Complexity: O(nlogK). n = points.length.
Space: O(n).

Approach2. Quick sort

The last solution is based on quick sort, we can also call it quick select. In the quick sort, we will always choose a pivot to compare with other elements. After one iteration, we will get an array that all elements smaller than the pivot are on the left side of the pivot and all elements greater than the pivot are on the right side of the pviot (assuming we sort the array in ascending order). So, inspired from this, each iteration, we choose a pivot and then find the position p the pivot should be. Then we compare p with the K, if the p is smaller than the K, meaning the all element on the left of the pivot are all proper candidates but it is not adequate, we have to do the same thing on right side, and vice versa. If the p is exactly equal to the K, meaning that we've found the K-th position. Therefore, we just return the first K elements, since they are not greater than the pivot.

Theoretically, the average time complexity is O(N) , but just like quick sort, in the worst case, this solution would be degenerated to O(N^2), and pratically, the real time it takes on leetcode is 15ms.

The advantage of this solution is it is very efficient.
The disadvatage of this solution are it is neither an online solution nor a stable one. And the K elements closest are not sorted in ascending order.

The short code shows as follows:

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        if(points == null || points.length == 0 || K < 1) {
            return points;
        }
        int left = 0, right = points.length - 1;
        while(left <= right) {
            
            int mid = helper(points, left, right);
            if(mid == K) break;
            if(mid < K) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        return Arrays.copyOfRange(points, 0, K);
    }
    
    private int helper(int[][] points, int left, int right) {
        int[] pivot = points[left];
        while(left < right){
            while(left < right && compare(points[right], pivot) >= 0) right--;
            points[left] = points[right];
            while(left < right && compare(points[left], pivot) <= 0) left++;
            points[right] = points[left];
        }
        points[left] = pivot;
        return left;
    }
    private int compare(int[] A, int[] B) {
        return A[0] * A[0] + A[1] * A[1] - B[0] * B[0] - B[1] * B[1];
    }
}

"Because in the quicksort, you have to take care of two sides of the pivot. But in quickselect, you only focus on the side the target object should be. So, in optimal case, the running time of quicksort is (n + 2 * (n/2) + 4 * (n/4)...), it has logn iterations. Instead, the running time of quickselect would be (n + n/2 + n/4 +...) it has logn iterations as well. Therefore, the running time of quicksort is O(nlogn), instead, the running time of quickselect of quickselect is O(n)
参考:https://leetcode.com/problems/k-closest-points-to-origin/discuss/220235/Java-Three-solutions-to-this-classical-K-th-problem.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容