# 0378. Kth Smallest Element in a Sorted Matrix ###### tags: `Leetcode` `FaceBook` `Medium` `Merge Sorted List` `Binary Search` Link: https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/ ## 思路 ### 思路一 Priority Queue $X=MIN(K,N)$ $O(X+KlogX)$ $O(X)$ x是heap的最大size,N是matrix的长度,建heap需要O(X),然后一共拿K次最小值,每次O(logX) 跟[0023. Merge k Sorted Lists](https://hackmd.io/SgY_aFxoRHurr9S9W_OI9A)有点像 用一个priority queue,存每个array里面最小的值,如果被pop,就换下一个 ### 思路二 Binary Search $O(Nlog(maxVal-minVal))$ N是col数+row数 binary search最重要的是确定搜索范围 有两种搜索范围:index和range Most usually, when the array is sorted in one direction, we can use index as "search space", when the array is unsorted and we are going to find a specific number, we can use "range". two examples of these two "search space" 1. [index](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/) ( the array is sorted) 2. [range](https://leetcode.com/problems/find-the-duplicate-number/) (Unsorted Array) 这个方法有三个很重要的地方 - 由于column也是排过序的,所以在找count的时候,只需要O(N),原因是从第一行开始找,如果对于idx j,matrix[i][j]>mid,那么matrix[i+1][j]也一定大于mid,所以在跑i的回圈的时候(一共跑了matrix.length次)j最多会移动matrix[0].length次,因此时间复杂度为O(N) - 之前写mid是用 ```int mid = (start+end)/2```,在没有overflow的情况下,通常都是正确的,mid永远都靠近start,但这道题就不对,原因是,这道题有负数测资,例如start=-5, end=-4的时候mid就会等于-4,靠近end,而不是靠近start,就会进入无穷回圈,解决方法就是**无论什么题都写```int mid = start+(end-start)/2```** - 为什么左边界lo一定在matrix里面,因为binary search找到的值,一定是让count=k的第一个值,既然这个值可以让count从k-1变成k,那么它一定在matrix里面 ## Code ### 思路一 ```java= class Solution { public int kthSmallest(int[][] matrix, int k) { Queue<Pair<Integer, Integer>> pq = new PriorityQueue<>((a,b)->(matrix[a.getKey()][a.getValue()] - matrix[b.getKey()][b.getValue()])); for(int i = 0;i < Math.min(matrix.length,k);i++){ pq.add(new Pair<>(i,0)); } for(int i = 0;i < k-1;i++){ Pair<Integer,Integer> small = pq.poll(); if(small.getValue()+1<matrix[small.getKey()].length){ pq.add(new Pair<>(small.getKey(), small.getValue()+1)); } } return matrix[pq.peek().getKey()][pq.peek().getValue()]; } } ``` ### 思路二 ```java= 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; 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; } } ```