/**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