Find the kth smallest number in at row and column sorted matrix.
Example
Given k = 4
and a matrix:
[
[1 ,5 ,7],
[3 ,7 ,8],
[4 ,8 ,9],
]
return 5
Challenge
http://www.cnblogs.com/sherylwang/p/5603991.html 的程序不是那么清楚,算法分析的表述是错误的,但是思路是很有启发性的。
O(k log n), n is the maximal number in width and height.
使用优先队列可以在log时间内找到最小值,所以只要不断的pop出最小值, 第k个就是答案。
那么,对于i,j从队列中剔除的时候,应该在压入那些“嫌疑犯”呢?
是i+1,j么? 是i, j+1么?
是的,但是理由并不是如上述网址所提供的那样。
首先,如果这样扫描,其实是在平行于对角线不断的压入。(左上三角)
我们必须要找到比i,大的最小的那几个数,保证队列的正确性。
所以, 如果只考虑+1,j 和 i, j+1, 并不具有说服力。
只要两个坐标合起来都为i+j+1的,都是“嫌疑犯”。
但是如果看一下整个队列压入的过程,如果某个数还没被压入,说明他左边的或者上面的那个数还没弹出,所以这样的做法是正确的,只是不太好证明
class Solution {
public:
/**
* @param matrix: a matrix of integers
* @param k: an integer
* @return: the kth smallest number in the matrix
*/
int kthSmallest(vector<vector<int> > &matrix, int k) {
// write your code here
priority_queue<int, vector<int> ,greater<int>> pqi;
const int m = matrix.size();
const int n = matrix[0].size();
unordered_map<int, vector<int>> map;
bool visited[m][n];
memset(visited, 0, sizeof(visited));
vector<int> res = {matrix[0][0]};
pqi.push(matrix[0][0]);
vector<int> temp ={0,0};
map[matrix[0][0]] = temp;
visited[0][0] = true;
for (int sum = 1; sum <= k ; sum++) {
int val = pqi.top();
pqi.pop();
res.push_back(val);
int i = map[val][0];
int j = map[val][1];
map[val].erase(map[val].begin());
map[val].erase(map[val].begin());
if (i + 1 < m && !visited[i + 1][j]) {
pqi.push(matrix[i + 1][j]);
visited[i + 1][j] = true;
if (map.find(matrix[i + 1][j]) == map.end()) {
vector<int> temp ={i + 1, j};
map[matrix[i + 1][j]] = temp;
} else {
map[matrix[i + 1][j]].push_back(i + 1);
map[matrix[i + 1][j]].push_back(j);
}
}
if (j + 1 < n && !visited[i][j + 1]) {
pqi.push(matrix[i][j + 1]);
visited[i][j + 1] = true;
if (map.find(matrix[i][j + 1]) == map.end()) {
vector<int> temp ={i, j + 1};
map[matrix[i][j + 1]] = temp;
} else {
map[matrix[i][j + 1]].push_back(i);
map[matrix[i][j + 1]].push_back(j + 1);
}
}
}
int r = res.back();
return r;
}
};