思路:
1.使用最小堆
我的做法就是使用最小堆来存放那些可能的最小值,一个值为当前最小值,那么下一个最小值会是它的右边和下边的那个值,因此要把这两个都放进最小堆里面去,为了防止存放重复的数字还搞了个布尔数组。
class Solution {
public int kthSmallest(int[][] matrix, int k) {
if(matrix == null || matrix[0].length < 1){
return 0;
}
int m = matrix.length;
int n = matrix[0].length;
class Node{
int val;
int i;
int j;
Node(int i,int j,int val){
this.val = val;
this.i = i;
this.j = j;
}
}
boolean[][] visited = new boolean[m][n];
visited[0][0] = true;
PriorityQueue<Node> pq = new PriorityQueue<>(new Comparator<Node>(){
public int compare(Node a,Node b){
return a.val - b.val;
}
});
Node tmp = new Node(0,0,matrix[0][0]);
pq.add(tmp);
while(k > 0){
tmp = pq.poll();
int r = tmp.i;
int c = tmp.j;
if(r + 1 < m && c + 1 < n){
if(!visited[r][c+1]){
pq.add(new Node(r,c+1,matrix[r][c+1]));
visited[r][c+1] = true;
}
if(!visited[r+1][c]){
pq.add(new Node(r+1,c,matrix[r+1][c]));
visited[r+1][c] = true;
}
}else if(r + 1 < m){
if(!visited[r+1][c]){
pq.add(new Node(r+1,c,matrix[r+1][c]));
visited[r+1][c] = true;
}
}else if(c + 1 < n){
if(!visited[r][c+1]){
pq.add(new Node(r,c+1,matrix[r][c+1]));
visited[r][c+1] = true;
}
}
k--;
}
return tmp.val;
}
}
看了别人的做法以后,觉得自己真是野路子,别人是这样做的,相当于n路合并的那道题,把n行的开头都存入堆里,如果某行的第一个是最小值,就将它的下一个元素存储在最小堆里。直到找到第K个最小值
class Solution {
public int kthSmallest(int[][] matrix, int k) {
if(matrix == null || matrix[0].length < 1){
return 0;
}
int n = matrix[0].length;
class Node{
int val;
int i;
int j;
Node(int i,int j,int val){
this.val = val;
this.i = i;
this.j = j;
}
}
PriorityQueue<Node> pq = new PriorityQueue<>(new Comparator<Node>(){
public int compare(Node a,Node b){
return a.val - b.val;
}
});
for(int t = 0;t < n;t++){
pq.add(new Node(t,0,matrix[t][0]));
}
while(k > 1){
Node tmp = pq.poll();
k--;
if(tmp.j == n-1){
continue;
}
pq.add(new Node(tmp.i,tmp.j+1,matrix[tmp.i][tmp.j+1]));
}
return pq.poll().val;
}
}
2.使用二分查找法
这篇博客讲解的较详细
class Solution {
public int kthSmallest(int[][] matrix, int k) {
if(matrix == null || matrix[0].length < 1){
return 0;
}
int n = matrix.length;
int left = matrix[0][0];
int right = matrix[n-1][n-1];
while(left < right){
int mid = left + right >> 1;
int count = findSmaller(matrix,mid);
if(count >= k){
right = mid;;
}else{
left = mid+1;
}
}
return right;
}
public int findSmaller(int[][] matrix,int target){
int row = matrix.length - 1;
int col = 0;
int count = 0;
while(row >= 0 && col < matrix.length){
if(matrix[row][col] <= target){
col++;
count += row + 1;
}else{
row--;
}
}
return count;
}
}