当前位置: 首页 > 知识库问答 >
问题:

求排序矩阵中_present_的第K个最小元素

姬熙云
2023-03-14

我的问题是受到这个特殊的SO评论的启发,这个评论没有得到回答(我自己也面临这个问题):

我试图找到排序矩阵中第K个最小的元素:

给定一个nxn矩阵,其中每个行和列都按升序排序,返回矩阵中第k个最小的元素
请注意,它是排序顺序中的第k个最小元素,而不是第k个独立元素

输入:矩阵=[[1,5,9],[10,11,13],[12,13,15],[12,13,15],k=8
输出:13
说明:矩阵中的元素是[1,5,9,10,11,12,13,13,15],第8个最小的数字是13

我的代码是这样的:

class Solution {
public:
    int kthSmallest(vector<vector<int>>& matrix, int k) {
        int lowest=INT_MAX, highest=INT_MIN;
        for(vector<int> row: matrix) {
            lowest=min(lowest, row[0]);
            highest=max(highest, row[row.size()-1]);
        }
        
        while(lowest<highest) {
            int mid=lowest+(highest-lowest+1)/2;
            int places=0;
            
            for(int i=0; i<matrix.size(); i++) {
                places+=(upper_bound(matrix[i].begin(), matrix[i].end(), mid)-matrix[i].begin());
            }
            if(places<=k) lowest=mid;      //this gives a number _not_ in the matrix (14)
            else highest=mid-1;
            // if(places<k) lowest=mid+1;  //this gives a number _in_ the matrix (13)
            // else highest=mid;   //also use mid=lowest+(highest-lowest)/2 instead;
        }
        
        return lowest;
    }
};

注释代码返回矩阵中存在的数字(13),而未注释代码返回矩阵中不存在的14

有什么好处?找到矩阵中的数字背后的直觉是什么?这里是ideone的工作代码。

共有1个答案

姜良哲
2023-03-14

让我给出另一种解决这个问题的方法,因为行和列是按升序排序的,对于矩阵中位于(x,y)位置的每个元素elem,如果它们是有效索引,那么位于(x1,y)的元素和元素(x1,y1)都小于elem

然后我们确定矩阵中的最小元素是矩阵[0][0],如果我们去掉这个元素,最小的元素就是矩阵[0][1]和矩阵[1][0]之间的最小元素。如果我们不停地移除元素,情况就会如此。

我们的算法将把每个候选元素放在一个最小的堆(优先级队列)中,这些元素在某个时候是矩阵中剩余的最小元素(我们不会直接修改矩阵),首先堆将只包含(0,0)处的元素,并且它在矩阵中索引,这样我们就可以快速定位它,表示为对

我们的步骤如下,弹出堆中最小的元素,将两个新的候选元素放入堆中最小,并重复直到弹出k元素。

您可能已经注意到,我们的堆中会有重复的数字,因为一个数字可以由堆顶部的元素和堆左侧的元素插入堆中,我们不希望这样,所以让我们来解决这个问题。

现在,只有当我们弹出的元素在第一行时,我们才会得到右边的元素。如果我们这样做,堆中就不会有任何重复的索引,但是,这能工作吗?,这个问题的答案是肯定的,因为列和行是有序的,所以我们不可能得到一个最小值,而不得到它上面和它左边的所有元素,我们仍然在确保至少有一种方法可以按升序到达每个元素。

您还应该注意到,我们最多在堆中插入2*k个元素。

实现细节:我假设矩阵中至少有k个元素。

typedef pair<int, int> pii;
typedef pair<int, pair<int, int>> matrixValue;

int kthSmallest(vector<vector<int>>& matrix, int k) {
    priority_queue<matrixValue, vector<matrixValue>, greater<>> priorityQueue;

    matrixValue smallest = matrixValue(matrix[0][0], pii(0, 0));

    priorityQueue.push(smallest);

    for (int i = 1; i < k; ++i) {
        matrixValue iterSmallest = priorityQueue.top();
        priorityQueue.pop();

        int x = iterSmallest.second.first;
        int y = iterSmallest.second.second;

        if ( x == 0 and y + 1 < matrix[0].size() ) {
            priorityQueue.push(matrixValue(matrix[x][y + 1], pii(x, y + 1)));
        }
        if ( x + 1 < matrix.size() ) {
            priorityQueue.push(matrixValue(matrix[x + 1][y], pii(x + 1, y)));
        }
    }

    return priorityQueue.top().first;
}
 类似资料:
  • 这是一个面试问题。 在具有排序行和列的矩阵中找到Kth最小元素。 Kth最小元素是中的一个,例如,这是否正确?

  • 所以我正在研究一个Leetcode问题,我的代码在某些情况下有效,但在某些情况下失败。 问题是: 给定一个矩阵,其中每个行和列都按升序排序,找出矩阵中第k个最小的元素。 请注意,它是排序顺序中的第k个最小元素,而不是第k个独立元素。 例子: 返回: 13 我的方法是使用minHeap,即使它声明数组已经排序,我仍然需要确保我已经将它从最小值排序到最大值。 这是我的代码: 以下是我的意见: 以下是输

  • 这是一个面试问题。 在排序的行(但不是排序的列)和行之间没有关系的矩阵中查找第k个最小元素。(第一行和第n行之间没有关系——我们只知道每一行都是按升序排列的) 输入示例如下: 这种情况下的结果是 因为20是这个矩阵中第五小的元素。 我首先想到将所有元素添加到minHeap中,然后轮询元素,同时每次迭代从k中减去一个,直到我们得到答案。我还考虑为O(m*n)解决方案实现快速选择,尽管这些解决方案并没

  • 我知道以前有人问过这个问题,但这个问题是关于我的具体代码。我试图做一个psuedo-QuickSelect算法,将k与排序矩阵子区间的中点进行比较。 我一直收到一个超时错误。 以下是矩阵: 下面是我的代码: 我将元组传递给,其中包含区间的endpoint的。因此,如果我想搜索整个矩阵,我会传递和。将查看子区间,根据endpoint的行号确定中点,计算小于中点的元素数量,将其与进行比较。如果小于小于

  • 我最近接受了一家社交媒体公司的面试,在那里我被问到了以下问题。 有k个长度为m的未排序数组。目标是在给定a 我提出了两个可能的解决方案: null 对于使用quickselect查找第b个最小元素的第一步,平均时间总共从O(km)到O(km*log(m))。第二步时间复杂度为O(km)。最后一步是在C中的第a和第b个最小元素之间寻找元素,取O((b-a)log(kb))。因此,total在时间上需

  • 这可能是微软的面试问题。 从排序的数组中找出第k个最小的元素(忽略重复项) [编辑]:数组可能包含重复项(未指定)。 想了很多次,但仍然质疑自己:还有更好的解决方案吗? 取最大堆 时间复杂度:O(NlogK) 空间复杂度:O(K) 这些元素可能是重复的。所以,通过与以前的元素进行比较来检查是否有唯一的元素 还可以使用改进版的快速排序分区算法。但它可能会导致最坏的情况,因为数组已经排序<这里出现了两