给定一个 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 个元素时循环结束。
算法:
- 这个想法是使用最小堆。创建一个最小堆来存储元素
- 从头到尾遍历第一行并从第一行构建最小元素堆。堆条目还存储行号和列号。
- 现在运行循环 k 次以在每次迭代中从堆中提取最小元素
- 从 Min-Heap 获取最小元素(或根)。
- 查找最小元素的行号和列号。
- 用同一列中的下一个元素替换 root,并对 root 进行最小堆化。
- 打印最后提取的元素,即第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 贡献。
复杂度分析:
- 时间复杂度:上述解决方案涉及以下步骤。
- 构建一个需要 O(n) 时间的最小堆
- 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
在范围内使用二分搜索:
这种方法使用二分搜索来迭代可能的解决方案。我们知道
- 答案 >= mat[0][0]
- 答案 <= 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]) )
- 我们调用 getElementsGreaterThanOrEqual函数log ( abs(Mat[0][0] – Mat[n-1][n-1]) ) 次
- getElementsGreaterThanOrEqual 的时间复杂度是 O(n logn) 因为我们在那里进行了 n 次二分搜索。
- 空间复杂度: O(1)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。