编程语言
首页 > 编程语言> > 编程题:行和列已排序的矩阵,求其从小到大的第k个元素。

编程题:行和列已排序的矩阵,求其从小到大的第k个元素。

作者:互联网

问题,已知矩阵A,例如:

\begin{bmatrix} 1 & 3 & 8 & 9 \\ 2 & 4 & 9 & 12 \\ 4 & 7 & 10 & 13 \\ 6 & 8 & 11 & 15 \end{bmatrix}

每一行和每一列都是递增的,求从小到大排的第k个元素是多少?

方法1:基本思路是从最小的元素开始找,依次找,直到找到第k个元素,由于每一行都是递增的,可以在每一行都设定一个起始读位置index,表示该行已读取几个元素,下一次要读取该行的哪个元素,每次读取每一行的一个元素,那么这些元素的必然有一个是最小值,取出最小的元素,相应的行的index加1。以我们给出的矩阵为例,最开始所有行均从0开始,我们扫描所有行的首元素,第一个读取的是A[0,0]且第一行的index变为1,其他行不变,继续扫描,第二个读的是A[1,0],第二行的index变为1,这样一次读下去,直到取第k个元素。设行数为n,由于每次都会做n次查找故复杂度为o(k\times n),代码实现如下:

int kthSmallest(vector<vector<int>> &matrix, int k)
{
	size_t row = matrix.size();
	size_t col = matrix[0].size();
	if (row == 0 || col == 0)
		return -1;
	int *minRows=new int[row]();//用于存储每行的读取索引位置,并初始化为0。
	if (k > row * col || k<0)//防止错误。
		return -1;
	int rs;
	int tmp;
	for (int cnt = 1; cnt <= k; cnt++)
	{
		int min_val = INT_MAX;//每次比较都需要初始化,注意该变量定义的位置
		for (int row_index = 0; row_index < row; row_index++)
		{
			if (minRows[row_index] < col)//注意这个判断条件一定要加上,防止越界
			{
				if (matrix[row_index][minRows[row_index]] < min_val)
				{
					min_val = matrix[row_index][minRows[row_index]];
					tmp = row_index;
				}
			}
		}
		minRows[tmp]++;//更新相应行中最小值的位置,要注意此处的位置,是在row轮循环之后才能找出最小值
		if (cnt == k)
			rs = min_val;
	}
    delete [] minRows;
    return rs;
}

方法2:进一步利用矩阵的行列均递增的特性,首先可以确定A[0,0]肯定是最小的,那么第二步呢,我们要找剩下的里面最小的,显然不能直接找到,但可以确定最小必然是A[0,1]A[1,0],这就是我们的思路,虽然找不到剩下最小的,但可以找到最小的集合,这样对这个集合排序,取出最小的元素就可以了。这样,我们得到了我们整体的思路,读取第一个元素之后开始,我们维持一个可能含有最小元素的集合,这个集合是排序的,取出一个就是最小的,那么每次取出第一个最小的之后,可能的最小元素只可能会是最小元素右边和下边的两个元素(可能不存在)与之前最小元素集合的并集,这样依次递推直到取出第k个即可,排序集合可以用priority_queue实现,每次会弹出最顶上的最小元素,其复杂度为o(k\times log(2k)),我们给出代码实现:

int kthSmallest(vector<vector<int>> matrix, int k) {
	if (matrix.empty() || k <= 0)
		return 0;
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;
	int row = matrix.size();
	int col = matrix[0].size();
	vector<vector<int>> visited(row, vector<int>(col, 0));
	que.push(make_pair(matrix[0][0], 0 * col + 0));
	visited[0][0] = 1;
	while (k--)
	{
		auto pairVal = que.top();
		que.pop();
		if (k == 0)
			return pairVal.first;
		int i = pairVal.second / col;
		int j = pairVal.second%col;
		if (i + 1 < row&&visited[i + 1][j] == 0)
		{
			que.push(make_pair(matrix[i + 1][j], (i + 1)*col + j));
			visited[i + 1][j] = 1;
		}
		if (j + 1 < col&&visited[i][j + 1] == 0)
		{
			que.push(make_pair(matrix[i][j + 1], i*col + (j + 1)));
			visited[i][j + 1] = 1;
		}
	}
}

 

标签:编程,matrix,int,元素,行和列,最小,求其,col,row
来源: https://blog.csdn.net/fangfanglovezhou/article/details/112758922