给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。
看完题解,自己也写了一遍,不过还是理解原理重要
class Solution {
public int kthSmallest(int[][] matrix, int k) {
PriorityQueue<Tuple> pq = new PriorityQueue<>();
for(int i=0;i<matrix[0].length;i++)
pq.add(new Tuple(0,i,matrix[0][i]));
for(int i=0;i<k-1;i++) {
Tuple t = pq.poll();
if(t.x==matrix.length-1)
continue;
pq.add(new Tuple(t.x+1,t.y,matrix[t.x+1][t.y]));
}
return pq.poll().val;
}
class Tuple implements Comparable<Tuple>{
int x;
int y;
int val;
public Tuple() {
}
public Tuple(int x, int y, int val) {
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo(Tuple t) {
return this.val - t.val;
}
}
}
参考自http://www.cnblogs.com/mydesky2012/p/5763967.html
//优先级队列,是从jdk1.5开始提供的新的数据结构接口
//如果不提供Comparator的话,优先队列中元素默认按自然顺序排列
//每次从队列中取出的是具有最高优先权的元素。
import java.util.PriorityQueue;
/**
* 已知一个n*m的矩阵,每一行、每一列都是有序的。
* 求这个矩阵中第k小的元素
* @author i333083
*
*/
public class KthSmallestEleInSortedMatrix {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] a = new int[][]{{1,5,9,11},{2,6,10,14},{3,7,13,15}};
System.out.println(kthSmallest(a,11));
}
//求矩阵中第k小的元素
public static int kthSmallest(int[][] matrix,int k){
int rows = matrix.length; //矩阵的行数
int cols = matrix[0].length;//列数
//优先队列
PriorityQueue<Tuple> queue = new PriorityQueue<Tuple>(); //入队列
/**
* 这里有一个设计非常巧妙的地方,将第一行升序的序列先入队列,根据Tuple类型的定义,最小的元素将会在队首。
* 每当队首元素出队列后,都将其所在列的下一个元素入队列,直到最后一行;
* 这样,就可以比较一个元素的同一行与同一列中相邻的元素中哪个较小,从而保证队首元素始终是矩阵中所有元素的最小值
*/
for(int j = 0; j < cols; ++j)
queue.add(new Tuple(0,j,matrix[0][j]));
//进行k-1次出队、入队,最后队首元素一定是所有元素中的第k小
for(int i = 0; i < k - 1; ++i){
Tuple p = queue.poll(); //出队列
System.out.print(p.val + " ");
if(p.x == rows - 1) //若是最后,则没有元素需要入队列了
continue;
queue.add(new Tuple(p.x + 1,p.y,matrix[p.x + 1][p.y]));
}
return queue.poll().val;
}
}
//实现Comparable接口要覆盖compareTo方法, 在compareTo方法里面实现比较
//自定义一个数据结构-元组,继承自comparable接口
class Tuple implements Comparable<Tuple>{
int x;
int y;
int val;
public Tuple(int x,int y,int val){
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo(Tuple t){
return this.val - t.val; //若新加入的元素较小,则排在队首
}
}
解决方案1:堆
这是我的解决方案的一步:
- 从第一行构建一个minHeap元素。
- 执行以下操作k-1次:
每次轮询根(堆中的顶部元素)时,您需要知道该元素的行号和列号(因此我们可以在这里创建一个元组类),替换它root与同一列中的下一个元素。
完成此问题后,请多考虑一下:
- 对于这个问题,您还可以从第一列构建一个min Heap,并执行与上面类似的操作。(将root替换为同一行中的下一个元素)
- 更重要的是,这个问题与Leetcode373找到最小和的K对完全相同,我使用相同的代码打败了96.42%,解决了这个问题之后,你可以查看这个链接:
https://discuss.leetcode。 COM /主题/ 52953 /股,我的解决方案-这拍,96-42
public class Solution {
public int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
PriorityQueue<Tuple> pq = new PriorityQueue<Tuple>();
for(int j = 0; j <= n-1; j++) pq.offer(new Tuple(0, j, matrix[0][j]));
for(int i = 0; i < k-1; i++) {
Tuple t = pq.poll();
if(t.x == n-1) continue;
pq.offer(new Tuple(t.x+1, t.y, matrix[t.x+1][t.y]));
}
return pq.poll().val;
}
}
class Tuple implements Comparable<Tuple> {
int x, y, val;
public Tuple (int x, int y, int val) {
this.x = x;
this.y = y;
this.val = val;
}
@Override
public int compareTo (Tuple that) {
return this.val - that.val;
}
}
解决方案2:二进制搜索
我们在这里完成,但让我们以另一种方式思考这个问题:
任何二进制搜索的关键点是找出“搜索空间”。对我来说,我认为有两种“搜索空间” - 索引和范围(从最小数字到最大数字的范围)。最常见的情况是,当数组按一个方向排序时,我们可以使用索引作为“搜索空间”,当数组未排序并且我们要查找特定数字时,我们可以使用“范围”。
让我举两个这两个“搜索空间”的例子
- index - 一堆例子 - https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/(数组已排序)
- 范围 - https://leetcode.com/problems/find-the-duplicate-number/(未排序数组)
我们没有使用索引作为“搜索空间”来解决这个问题的原因是矩阵在两个方向上排序,我们找不到一种线性方式来映射数字及其索引。
public class Solution {
public int kthSmallest(int[][] matrix, int k) {
int lo = matrix[0][0], hi = matrix[matrix.length - 1][matrix[0].length - 1] + 1;//[lo, hi)
while(lo < hi) {
int mid = lo + (hi - lo) / 2;
int count = 0, j = matrix[0].length - 1;
for(int i = 0; i < matrix.length; i++) {
while(j >= 0 && matrix[i][j] > mid) j--;
count += (j + 1);
}
if(count < k) lo = mid + 1;
else hi = mid;
}
return lo;
}
}