题目
思路
左上角为整个矩阵的最小值small,右上角为整个矩阵的最大值big。那么取中间值mid(small<=mid<=big),由于整个
数组按行、按列都是递增的序列,因此整个矩阵中,不大于mid的数在在锯齿线的左上方,如下图所示:
假设mid = 12,那么不大于12的数是在锯齿线的左上方。
每次找不大于mid的数,从左下角开始,也就是从(N-1,0)元素开始。
1)如果当前矩阵中当前数cur比mid大,那么这一行之后的元素就都比mid大,这一行之后的列就不用继续比较,直接跳到上一行。
2)如果当前矩阵中的当前数cur小于等于mid,那么说明这一列的前面的数就都小于等于mid,假如当前是第 i 行,那么就有 i+1 个数小于等于mid。
结束条件:如果行下标比0小,或者列下标超出N-1。
总结: 这样就能知道有多少数小于等于mid,用count表示。left、right分别初始化为最小值和最大值。
- 如果count大于等于k,就说明第k个数小于等于mid。right = mid;
- 如果count小于k,就说明第k个数大于mid。left = mid+ 1
如果left == right ,那么就返回left。
例子:
left,right | mid | count | count>=k |
---|---|---|---|
1,15 | 8 | 1+1=2 | false |
9,15 | 12 | 3+2+1=6 | false |
13,15 | 14 | 3+3+2=8 | true |
13,14 | 13 | 3+3+3=8 | true |
13,13 |
left =13, right = 13
,结束循环,返回left值。
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int n = matrix.length;
int left = matrix[0][0];
int right = matrix[n - 1][n - 1];
while(left < right){
int mid = left + ((right - left) >> 1);
if(compare(matrix,n,k,mid)){
right = mid;
}else{
left = mid + 1;
}
}
return left;
}
public boolean compare(int[][] matrix,int n,int k,int mid){
int i = n - 1;
int j = 0;
int count = 0;
while(i >= 0 && j < n){//if false then over ,it's not need to compare with numbers which are bigger than mid
if(matrix[i][j] <= mid){
count+=(i + 1);
j++;
}else{
i--;
}
}
return count>=k;
}
}