LeetCode378 有序矩阵中第K小的元素

原题目

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix

题目分析

方法一:
用一维数组存储,快排,返回一维数组第k个即可
方法二:
找规律,如果要判断一个值是数组中的第几小元素,只要统计每一行小于该值的个数,将每一行个数加起来就是该数的位置。其次,如何更快判断该数是第几小元素,方式一,对其每一行进行二分查找,该过程时间复杂度O(nlogn);方式二改进,利用规律,从第一行最后一个元素从后往前找第一个小于等于该元素的下标加1,则代表当前行小于该值的个数,接下来找下一行第一个小于当前值的元素就从上一行当前列开始,而不用从最后开始,因为下一行的元素是始终大于上一行一一对应的元素,因为在上一行已经判断了当前列到最后一列是大于该元素的,则下一行当前列也是大于该元素的,该过程时间复杂度O(n+n)。然后所以利用二分查找,取最大最小值的平均值,判断其在第几位,如果与要求的位数一样且左右值大小相等返回
起初疑问:为什么返回的值就一定是数组中的值,而不是其他值。因为如果假设这个值不在数组中,那么小于这个值的元素个数要么小于k,要么大于等于k,小于k则left=mid+1往右移,大于等于k则right=mid往左移,则要求的元素,始终夹在两者中间
也就是说,如果小于k,left会不断往右移至第一个等于k的值的地方,而第一个等于k的元素一定是数组中的元素,因为其他值都是如果等于k一定是在要求的元素和下一元素之间的值,如果等于k则right左移至第一个等于k的地方
例如:
left=12 要求的值13 right=20
假设12和14~20都不存在数组中,则left的个数一定小于k,而right的个数一定等于k,所以mid=(12+20)/2=16,mid的个数等于k,则right左移至16,继续mid=(12+16)/2=14
mid的个数等于k,则right左移至14,继续mid=(12+14)/2=13,right左移至13,继续mid=(12+13)/2=12,left右移至12+1=13,左右相等,返回该值
注意:为了避免出现死循环,我们因取左中位

完整代码

方法一:

int cmp(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;
}

int kthSmallest(int** matrix, int matrixSize, int* matrixColSize, int k){
    int *s=(int *)malloc(sizeof(int)*(matrixSize*matrixSize+1));
    int l=0;
    for(int i=0;i<matrixSize;i++)
        for(int j=0;j<matrixColSize[i];j++)
        {
            s[l++]=matrix[i][j];
        }
    qsort(s,matrixSize*matrixSize,sizeof(int),cmp);
    return s[k-1];
}

方法二:

方式一:略
方式二:

int kthSmallest(int** matrix, int matrixSize, int* matrixColSize, int k){
    int n=matrixSize;
    int low=matrix[0][0],high=matrix[n-1][n-1];
    while(low<high)
    {
        int mid=(high+low)>>1;
        int count=0,j=n-1;
        for(int i=0;i<n;i++)
        {
            while(j>=0&&matrix[i][j]>mid)j--;
            count+=j+1;
        }
        if(count<k)
            low=mid+1;
        else
            high=mid;
    }
    return low;
}

同方式二

int kthSmallest(int** matrix, int matrixSize, int* matrixColSize, int k){
    int n=matrixSize;
    int low=matrix[0][0],high=matrix[n-1][n-1];
    while(low<high)
    {
        int mid=(high+low)>>1;
        int count=0,j=n-1;
        for(int i=0;i<n;i++)
        {
            while(j>=0&&matrix[i][j]>mid)j--;
        count+=j+1;
        }
        if(count<k)
            low=mid+1;
        else
            high=mid;
    }
    return low;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Baal Austin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值