【Leetcode&C语言】973. K Closest Points to Origin

目录

问题描述

举例说明

限制

实现

Heapify最大堆O(nlogk)

关于时间复杂度

关于使用最小堆解决的弊端


 

问题描述

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.)

 在平面上有一些点。找到K个距离(0,0)最近的点(在这道题,平面中两点之间距离是欧式距离)。

你可以以任意顺序返回答案。保证答案是唯一的(除了顺序)。

举例说明

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.)

例1:
输入:点=[[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:
输入:点=[[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

实现

Heapify最大堆O(nlogk)

 声明新的结构体Dist用来存储索引和对应索引的一维数组各元素平方和(即距离)。

之后创建长度为pointsSize(点的个数)的Dist类型的数组,存储所有点的索引和与(0,0)相差的距离。

关于时间复杂度

然后创建长度为K的Dist类型数组maxHeap,用来将所给数组的前K个点元素制成最大堆(添加,sift down,添加,sift down.... 这样的时间复杂度为O(klogk))。之后再遍历n-k次,如果距离小于maxHeap的第一个元素就进行replace的操作(单个replace的时间复杂度为O(logk))。那么这样得到的时间复杂度就是nlogk。但是!!如果使用heapify制成最大堆的情况又是怎样的呢?heapify的时间复杂度为O(k),而replace操作的时间复杂度为O((n-k)logk),哪个数量级更大?如果不好判断又该如何合并呢?

解答:如果考虑时间复杂度的上边界,则有O(K) + O((n-k)logK) <  O(K) + O(nlogk) ,所以时间复杂度为 O(K) + O(nlogk) ,进而是O(nlogk)

源自:https://leetcode.com/problems/k-closest-points-to-origin/discuss/835544/could-anyone-tell-me-the-time-complexity-of-this-code/688340

关于使用最小堆解决的弊端

我们创建了一个最多包含M个元素的堆。在这个堆上的基本操作是O(logM)的。对于每一个元素,我们都可能要在这个堆上进行一次操作,所以时间复杂度是O(NlogM)的。

 

如果你一上来对数组中的所有元素组织成一个堆,这个过程是O(N)的,之后在这个巨大的堆中取前M个元素,时间复杂度是O(MlogN)的,综合这个过程,时间复杂度是:O(N + MlogN)的。

 

后一种方法有一个缺点,或者说是限制,就是需要在算法计算初始,就已知所有的数据。在Leetcode上这个问题中,这个条件可以满足。但是在实际中,数据很有可能是一点一点流进来的,而不是一次性给出的(比如用户的下单数据);同时,由于N巨大,很有可能维持一个包含N个元素的堆是不现实的,而维持一个包含M个元素的堆,是很简单的。比如要实时统计单笔订单金额最高的前100个订单,前一种方法只需要维护一个包含100个元素的堆,而后一种方法需要维护一个包含订单总量那么多元素的堆,而订单总量可能是一个天文数字

以上文字源于https://coding.imooc.com/learn/questiondetail/145066.html

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

typedef struct Dist Dist;
struct Dist{
  int index;
    int distance;
};

void siftDown(Dist **dist,int size,int index)
{
    while(index*2+1<size){
        int j = index*2+1;
        if(j+1<size && dist[j+1]->distance>dist[j]->distance)
            j++;
        if(dist[index]->distance>=dist[j]->distance)
            break;
        Dist *tmp = dist[index];
        dist[index]=dist[j];
        dist[j]=tmp;
        index=j;
    }
}

int** kClosest(int** points, int pointsSize, int* pointsColSize, int K, int* returnSize, int** returnColumnSizes){
    *returnSize = K;
    Dist **dist = malloc(sizeof(Dist)*pointsSize);
    for(int i=0;i<pointsSize;i++){
        dist[i]=malloc(sizeof(Dist));
    }
    
    for(int i=0;i<pointsSize;i++)
    {
        dist[i]->index = i;
        dist[i]->distance = points[i][0]*points[i][0]+points[i][1]*points[i][1];
    }
    
    Dist **maxHeap = malloc(sizeof(Dist)*K);
    for(int i=0;i<K;i++){
        maxHeap[i]=malloc(sizeof(Dist));
        maxHeap[i]->index = dist[i]->index;
        maxHeap[i]->distance = dist[i]->distance;
    }
    for(int i=(K<=2)?1:(K-2)/2;i>=0;i--)
    {
        siftDown(maxHeap,K,i);
    }
    
    for(int i=K;i<pointsSize;i++){
        if(dist[i]->distance < maxHeap[0]->distance)
        {
            maxHeap[0]=dist[i];
            siftDown(maxHeap,K,0);
        }
    }

    *returnColumnSizes = malloc(sizeof(int)*K);
    for (int i = 0; i < K; i++)
    {
        returnColumnSizes[0][i] = 2;
    }
    
    int **ret = malloc(sizeof(int*)*K);
    for(int i=0; i < K; i++){
        ret[i] = malloc(sizeof(int)*2);
    }
    
    for(int i=0;i<K;i++){
        ret[i][0]=points[maxHeap[i]->index][0];
        ret[i][1]=points[maxHeap[i]->index][1];
    }
    
    return ret;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值