/**Given a N*N Matrix.
All rows are sorted, and all columns are sorted.
Find the Kth Largest element of the matrix.
- 646 on November 23, 2010 | Report Duplicate */
/**For me, it is easier to think of the P-th smallest element
and then use K = N*N-P
For example we have a 4*4 matrix:
1 10 19 20
2 22 30 40
21 30 40 50
39 40 50 60
The numbers are trivial, but the orders and the positions are important.
[0,0] is the smallest.
Ignore the boundary case for now. Every element has two definite directions:
going right or down, which results a larger number.
It is simpler than Dajikstra, we only need to keep the unvisited frontier
elements in a priority queue. Every time we pop an element, mark it visited,
and immediately push in its two neighbors, i.e. right and down neighbors.
*/
/**In C++, the default priorit_queue is a max heap, especially when less-than
is defined.
*/
#include <vector>
#include <queue>
#include <algorithm>
#include <tuple>
#include <iostream>
#include <array>
using namespace std;
template <typename T>
class Solution{
typedef tuple<T, int, int> Element;
class ElementMore{
public:
bool operator() (const Element& lhs, const Element& rhs) const{
return get<0>(lhs) > get<0>(rhs);
}
};//class ElementLess
public:
T getSmallRank(vector<vector<T>> const& matrix, int const k){
if (matrix.empty()) return 0;
int const N = matrix.size();
if (N != matrix[0].size()) return 0;//not a square matrix
if (k < 1 || k > N*N) return 0;
//k is the desired rank to return
vector<vector<T>> visitFlag;
visitFlag.resize(matrix.size());
for(auto it = visitFlag.begin(); it != visitFlag.end(); ++it) it->resize(matrix.size());
//init visitFlag to all 0. label 1 for visited
Element element = make_tuple(matrix[0][0], 0, 0);//<value, row, col>
priority_queue<Element, vector<Element>, ElementMore> frontier;
frontier.push(element);
visitFlag[0][0] = 1;
for(int rank = 1; rank < k; ++rank){
element = frontier.top(); frontier.pop();
int const row = get<1>(element);
int const col = get<2>(element);
if (col + 1 < N && !visitFlag[row][col+1]){//element has a right neighbor
frontier.push(make_tuple(matrix[row][col+1],row,col+1));
visitFlag[row][col+1] = 1;
}//right neighbor
if (row + 1 < N && !visitFlag[row+1][col]){//has a down neighbor
frontier.push(make_tuple(matrix[row+1][col],row+1,col));
visitFlag[row+1][col] = 1;
}//down neighbor
}//for rank
return get<0>(frontier.top());
}//getSmallRankP
T getBigRank(vector<vector<T>> const& matrix, int const k){
return getSmallRank(matrix, matrix.size()*matrix.size()-k+1);
}
};
int main(){
cout<<"HEllo"<<endl;
array<int, 4> a = {1 , 10, 19, 20};
array<int, 4> b = {2 , 22, 30, 40};
array<int ,4> c = {21, 33, 40, 50};
array<int, 4> d = {39, 40, 51, 60};
//ranks: 1 ,2, 3, 4, 5, 6, 7
//elements: 1 ,2, 10, 19, 20, 21,22
//and rank 15 is 51
//and rank 16 is 60
vector<vector<int>> matrix;
matrix.resize(4);
matrix[0].assign(a.begin(),a.end());
matrix[1].assign(b.begin(),b.end());
matrix[2].assign(c.begin(),c.end());
matrix[3].assign(d.begin(),d.end());
Solution<int> s;
for(int ii = 1; ii <=7; ++ii){
auto result = s.getSmallRank(matrix,ii);
cout<<result<<endl;
}
cout<< s.getSmallRank(matrix, 15)<<endl<<endl;
cout<< s.getSmallRank(matrix, 16)<<endl<<endl;
cout<< s.getBigRank(matrix, 2)<<endl<<endl;
}
Solving problems is fun. But solving the same problem over and over is pain. Once solved, forever solved.
sourcecode
Tuesday, November 13, 2012
Kth Largest element of a sorted matrix
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment