📌  相关文章
📜  按行和按列排序的二维数组中的第 K 个最小元素 |设置 1

📅  最后修改于: 2021-10-28 01:58:17             🧑  作者: Mango

给定一个 nxn 矩阵,其中每一行和每一列都按非降序排序。在给定的二维数组中找到第 k 个最小的元素。
例子,

Input:k = 3 and array =
        10, 20, 30, 40
        15, 25, 35, 45
        24, 29, 37, 48
        32, 33, 39, 50 
Output: 20
Explanation: The 3rd smallest element is 20 

Input:k = 7 and array =
        10, 20, 30, 40
        15, 25, 35, 45
        24, 29, 37, 48
        32, 33, 39, 50 
Output: 30

Explanation: The 7th smallest element is 30

方法:所以想法是找到第k个最小元素。每一行和每一列都进行了排序。所以它可以被认为是 C 排序的列表,并且列表必须合并为一个列表,必须找出列表的第 k 个元素。所以方法是相似的,唯一的区别是当找到第 k 个元素时循环结束。
算法:

  1. 这个想法是使用最小堆。创建一个最小堆来存储元素
  2. 从头到尾遍历第一行并从第一行构建最小元素堆。堆条目还存储行号和列号。
  3. 现在运行循环 k 次以在每次迭代中从堆中提取最小元素
  4. 从 Min-Heap 获取最小元素(或根)。
  5. 查找最小元素的行号和列号。
  6. 用同一列中的下一个元素替换 root,并对 root 进行最小堆化。
  7. 打印最后提取的元素,即第k个最小元素

执行:

C++
// kth largest element in a 2d array sorted row-wise and
// column-wise
#include 
using namespace std;
 
// A structure to store entry of heap. The entry contains
// value from 2D array, row and column numbers of the value
struct HeapNode {
    int val; // value to be stored
    int r; // Row number of value in 2D array
    int c; // Column number of value in 2D array
};
 
// A utility function to minheapify the node harr[i] of a
// heap stored in harr[]
void minHeapify(HeapNode harr[], int i, int heap_size)
{
    int l = i * 2 + 1;
    int r = i * 2 + 2;
     if(l < heap_size&& r= n * n)
        return INT_MAX;
 
    // Create a min heap of elements from first row of 2D
    // array
    HeapNode harr[n];
    for (int i = 0; i < n; i++)
        harr[i] = { mat[0][i], 0, i };
 
    HeapNode hr;
    for (int i = 0; i < k; i++) {
        // Get current heap root
        hr = harr[0];
 
        // Get next value from column of root's value. If
        // the value stored at root was last value in its
        // column, then assign INFINITE as next value
        int nextval = (hr.r < (n - 1)) ? mat[hr.r + 1][hr.c]: INT_MAX;
 
        // Update heap root with next value
        harr[0] = { nextval, (hr.r) + 1, hr.c };
 
        // Heapify root
        minHeapify(harr, 0, n);
    }
 
    // Return the value at last extracted root
    return hr.val;
}
 
// driver program to test above function
int main()
{
    int mat[4][4] = {
        { 10, 20, 30, 40 },
        { 15, 25, 35, 45 },
        { 25, 29, 37, 48 },
        { 32, 33, 39, 50 },
    };
    cout << "7th smallest element is "
        << kthSmallest(mat, 4, 7);
    return 0;
}
 
// this code is contributed by Rishabh Chauhan


Java
// Java program for kth largest element in a 2d
// array sorted row-wise and column-wise
class GFG{
     
// A structure to store entry of heap.
// The entry contains value from 2D array,
// row and column numbers of the value
static class HeapNode
{
     
    // Value to be stored
    int val;
     
    // Row number of value in 2D array
    int r;
     
    // Column number of value in 2D array
    int c;
     
    HeapNode(int val, int r, int c)
    {
        this.val = val;
        this.c = c;
        this.r = r;
    }
}
 
// A utility function to minheapify the node
// harr[i] of a heap stored in harr[]
static void minHeapify(HeapNode harr[],
                       int i, int heap_size)
{
    int l = 2 * i + 1;
    int r = 2 * i + 2;
    int min = i;
     
    if(l < heap_size&& r= n * n)
        return Integer.MAX_VALUE;
     
    // Create a min heap of elements
    // from first row of 2D array
    HeapNode harr[] = new HeapNode[n];
     
    for(int i = 0; i < n; i++)
    {
        harr[i] = new HeapNode(mat[0][i], 0, i);
    }
     
    HeapNode hr = new HeapNode(0, 0, 0);
     
    for(int i = 1; i <= k; i++)
    {
         
        // Get current heap root
        hr = harr[0];
         
        // Get next value from column of root's
        // value. If the value stored at root was
        // last value in its column, then assign
        // INFINITE as next value
        int nextVal = hr.r < n - 1 ?
                      mat[hr.r + 1][hr.c] :
                      Integer.MAX_VALUE;
                       
        // Update heap root with next value
        harr[0] = new HeapNode(nextVal,
                               hr.r + 1, hr.c);
                                
        // Heapify root
        minHeapify(harr, 0, n);
    }
     
    // Return the value at last extracted root
    return hr.val;
}
 
// Driver code
public static void main(String args[])
{
    int mat[][] = { { 10, 20, 30, 40 },
                    { 15, 25, 35, 45 },
                    { 25, 29, 37, 48 },
                    { 32, 33, 39, 50 } };
                     
    int res = kthSmallest(mat, 4, 7);
     
    System.out.print("7th smallest element is "+ res);
}
}
 
// This code is contributed by Rishabh Chauhan


Python3
# Program for kth largest element in a 2d array
# sorted row-wise and column-wise
from sys import maxsize
 
# A structure to store an entry of heap.
# The entry contains a value from 2D array,
# row and column numbers of the value
class HeapNode:
    def __init__(self, val, r, c):
        self.val = val # value to be stored
        self.r = r # Row number of value in 2D array
        self.c = c # Column number of value in 2D array
 
# A utility function to minheapify the node harr[i]
# of a heap stored in harr[]
def minHeapify(harr, i, heap_size):
    l = i * 2 + 1
    r = i * 2 + 2
    if(l < heap_size and r n * n:
        return maxsize
 
    # Create a min heap of elements from
    # first row of 2D array
    harr = [0] * n
    for i in range(n):
        harr[i] = HeapNode(mat[0][i], 0, i)
 
    hr = HeapNode(0, 0, 0)
    for i in range(k):
 
        # Get current heap root
        hr = harr[0]
 
        # Get next value from column of root's value.
        # If the value stored at root was last value
        # in its column, then assign INFINITE as next value
        nextval = mat[hr.r + 1][hr.c] if (hr.r < n - 1) else maxsize
 
        # Update heap root with next value
        harr[0] = HeapNode(nextval, hr.r + 1, hr.c)
 
        # Heapify root
        minHeapify(harr, 0, n)
 
    # Return the value at last extracted root
    return hr.val
 
# Driver Code
if __name__ == "__main__":
    mat = [[10, 20, 30, 40],
        [15, 25, 35, 45],
        [25, 29, 37, 48],
        [32, 33, 39, 50]]
    print("7th smallest element is",
            kthSmallest(mat, 4, 7))
 
# This code is contributed by Rishabh Chauhan


C#
// C# program for kth largest element in a 2d
// array sorted row-wise and column-wise
using System;
 
class GFG{
     
// A structure to store entry of heap.
// The entry contains value from 2D array,
// row and column numbers of the value
class HeapNode
{
     
    // Value to be stored
    public int val;
     
    // Row number of value in 2D array
    public int r;
     
    // Column number of value in 2D array
    public int c;
     
    public HeapNode(int val, int r, int c)
    {
        this.val = val;
        this.c = c;
        this.r = r;
    }
}
 
// A utility function to minheapify the node
// harr[i] of a heap stored in harr[]
static void minHeapify(HeapNode []harr, int i, int heap_size){
    int l = 2 * i + 1;
    int r = 2 * i + 2;
   
    if(l < heap_size && r < heap_size && harr[l].val < harr[i].val && harr[r].val < harr[i].val){
            HeapNode temp = new HeapNode(0, 0, 0);
            temp=harr[r];
            harr[r]=harr[i];
            harr[i]=harr[l];
            harr[l]=temp;
            minHeapify(harr ,l,heap_size);
            minHeapify(harr ,r,heap_size);
        }
          if (l < heap_size && harr[l].val < harr[i].val){
            HeapNode temp = new HeapNode(0, 0, 0);   
            temp = harr[i];
            harr[i]=harr[l];
            harr[l]=temp;
            minHeapify(harr ,l,heap_size);
        }
}
 
// This function returns kth smallest
// element in a 2D array [,]mat
public static int kthSmallest(int[,] mat,int n, int k)
{
     
    // k must be greater than 0 and
    // smaller than n*n
    if (k < 0 || k > n * n)
    {
        return int.MaxValue;
    }
     
    // Create a min heap of elements
    // from first row of 2D array
    HeapNode []harr = new HeapNode[n];
     
    for(int i = 0; i < n; i++)
    {
        harr[i] = new HeapNode(mat[0, i], 0, i);
    }
     
    HeapNode hr = new HeapNode(0, 0, 0);
     
    for(int i = 0; i < k; i++)
    {
         
        // Get current heap root
        hr = harr[0];
         
        // Get next value from column of root's
        // value. If the value stored at root was
        // last value in its column, then assign
        // INFINITE as next value
        int nextVal = hr.r < n - 1 ?
                      mat[hr.r + 1, hr.c] :
                      int.MaxValue;
                       
        // Update heap root with next value
        harr[0] = new HeapNode(nextVal, hr.r + 1, hr.c);
                                
        // Heapify root
        minHeapify(harr, 0, n);
    }
     
    // Return the value at last
    // extracted root
    return hr.val;
}
 
// Driver code
public static void Main(String []args)
{
    int [,]mat = { { 10, 20, 30, 40 },
                   { 15, 25, 35, 45 },
                   { 25, 29, 37, 48 },
                   { 32, 33, 39, 50 } };
                     
    int res = kthSmallest(mat, 4, 7);
     
    Console.Write("7th smallest element is " + res);
}
}
 
// This code is contributed by Rishabh Chauhan


Javascript


C++
// kth largest element in a 2d array sorted row-wise and
// column-wise
#include
using namespace std;
 
int kthSmallest(int mat[4][4], int n, int k)
{
    // USING LAMBDA FUNCTION
    // [=] IN LAMBDA FUNCTION IS FOR CAPTURING VARIABLES WHICH
    // ARE OUT OF SCOPE i.e. mat[r]
    // NOW, IT'LL COMPARE ELEMENTS OF HEAP BY ELEMENTS AT mat[first][second]
      // Capturing the value of mat by reference to prevent copying
    auto cmp = [&](pair a,pair b){
        return mat[a.first][a.second] > mat[b.first][b.second];
    };
     
    //DECLARING priority_queue AND PUSHING FIRST ROW IN IT
    priority_queue,vector>,decltype(cmp)> pq(cmp);
    for(int i=0; i


C++
#include 
using namespace std;
 
// This returns count of elements in matrix less than of equal to num
int getElementsGreaterThanOrEqual(int num, int n, int mat[4][4]) {
    int ans = 0;
 
    for (int i = 0; i < n; i++) {
        // if num is less than the first element then no more element in matrix
        // further are less than or equal to num
        if (mat[i][0] > num) {
            return ans;
        }
        // if num is greater than last element, it is greater than all elements
        // in that row
        if (mat[i][n - 1] <= num) {
            ans += n;
            continue;
        }
        // This contain the col index of last element in matrix less than of equal
        // to num
        int greaterThan = 0;
        for (int jump = n / 2; jump >= 1; jump /= 2) {
            while (greaterThan + jump < n &&
                   mat[i][greaterThan + jump] <= num) {
                greaterThan += jump;
            }
        }
 
        ans += greaterThan + 1;
    }
    return ans;
}
 
// reuturs kth smallest index in the matrix
int kthSmallest(int mat[4][4], int n, int k) {
    //  We know the answer lies between the first and the last element
    // So do a binary search on answer based on the number of elements
    // our current element is greater than the elements in the matrix
    int l = mat[0][0], r = mat[n - 1][n - 1];
 
    while (l <= r) {
        int mid = l + (r - l) / 2;
        int greaterThanOrEqualMid = getElementsGreaterThanOrEqual(mid, n, mat);
 
        if (greaterThanOrEqualMid >= k)
            r = mid - 1;
        else
            l = mid + 1;
    }
    return l;
}
 
int main() {
    int n = 4;
    int mat[4][4] = {
        {10, 20, 30, 40},
        {15, 25, 35, 45},
        {25, 29, 37, 48},
        {32, 33, 39, 50},
    };
    cout << "7th smallest element is " << kthSmallest(mat, 4, 7);
    return 0;
}


Javascript


输出
7th smallest element is 30

以上代码由 RISHABH CHAUHAN 贡献。
复杂度分析:

  • 时间复杂度:上述解决方案涉及以下步骤。
    1. 构建一个需要 O(n) 时间的最小堆
    2. Heapify k 次需要 O(k Logn) 时间。
  • 空间复杂度: O(R),其中 R 是一行的长度,因为最小堆一次存储一行。

使用内置的 priority_queue :

通过使用比较器,我们可以在priority_queue中进行自定义比较。为此,我们将使用 priority_queue>。

执行 :

C++

// kth largest element in a 2d array sorted row-wise and
// column-wise
#include
using namespace std;
 
int kthSmallest(int mat[4][4], int n, int k)
{
    // USING LAMBDA FUNCTION
    // [=] IN LAMBDA FUNCTION IS FOR CAPTURING VARIABLES WHICH
    // ARE OUT OF SCOPE i.e. mat[r]
    // NOW, IT'LL COMPARE ELEMENTS OF HEAP BY ELEMENTS AT mat[first][second]
      // Capturing the value of mat by reference to prevent copying
    auto cmp = [&](pair a,pair b){
        return mat[a.first][a.second] > mat[b.first][b.second];
    };
     
    //DECLARING priority_queue AND PUSHING FIRST ROW IN IT
    priority_queue,vector>,decltype(cmp)> pq(cmp);
    for(int i=0; i
输出
7th smallest element is 30

在范围内使用二分搜索:

这种方法使用二分搜索来迭代可能的解决方案。我们知道

  1. 答案 >= mat[0][0]
  2. 答案 <= mat[N-1][N-1]

所以我们在这个范围上进行二分搜索,并在每次迭代中确定大于或等于我们当前中间元素的元素数。大于或等于当前元素的元素可以使用二进制搜索在 O( n logn ) 时间内找到。

C++

#include 
using namespace std;
 
// This returns count of elements in matrix less than of equal to num
int getElementsGreaterThanOrEqual(int num, int n, int mat[4][4]) {
    int ans = 0;
 
    for (int i = 0; i < n; i++) {
        // if num is less than the first element then no more element in matrix
        // further are less than or equal to num
        if (mat[i][0] > num) {
            return ans;
        }
        // if num is greater than last element, it is greater than all elements
        // in that row
        if (mat[i][n - 1] <= num) {
            ans += n;
            continue;
        }
        // This contain the col index of last element in matrix less than of equal
        // to num
        int greaterThan = 0;
        for (int jump = n / 2; jump >= 1; jump /= 2) {
            while (greaterThan + jump < n &&
                   mat[i][greaterThan + jump] <= num) {
                greaterThan += jump;
            }
        }
 
        ans += greaterThan + 1;
    }
    return ans;
}
 
// reuturs kth smallest index in the matrix
int kthSmallest(int mat[4][4], int n, int k) {
    //  We know the answer lies between the first and the last element
    // So do a binary search on answer based on the number of elements
    // our current element is greater than the elements in the matrix
    int l = mat[0][0], r = mat[n - 1][n - 1];
 
    while (l <= r) {
        int mid = l + (r - l) / 2;
        int greaterThanOrEqualMid = getElementsGreaterThanOrEqual(mid, n, mat);
 
        if (greaterThanOrEqualMid >= k)
            r = mid - 1;
        else
            l = mid + 1;
    }
    return l;
}
 
int main() {
    int n = 4;
    int mat[4][4] = {
        {10, 20, 30, 40},
        {15, 25, 35, 45},
        {25, 29, 37, 48},
        {32, 33, 39, 50},
    };
    cout << "7th smallest element is " << kthSmallest(mat, 4, 7);
    return 0;
}

Javascript


输出:

7th smallest element is 30

复杂性分析

  • 时间复杂度O( y * n*logn)
Where y =  log( abs(Mat[0][0] - Mat[n-1][n-1]) )
  1. 我们调用 getElementsGreaterThanOrEqual函数log ( abs(Mat[0][0] – Mat[n-1][n-1]) ) 次
  2. getElementsGreaterThanOrEqual 的时间复杂度是 O(n logn) 因为我们在那里进行了 n 次二分搜索。
  • 空间复杂度O(1)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程