思路
对一个数值范围在[1,m * n]的矩阵,每一行从左到右是递增的,每一列从上到下是递增的。
所以我们可以定义左右指针指向矩阵的初始和末尾,同时对每一次计算出的mid,累加矩阵中每一行,小于mid的元素个数cnt。
- 如果最终cnt >= k,说明小于二分出的中间节点mid的元素个数比题目要求的k还要多,需要调整右指针r的位置,使其下一轮在[l, mid]中搜索;
- 反之说明小于mid的元素个数比k要少,达不到k,需要调整左指针l的位置,使其下一轮在[mid + 1, r]中搜索。
重点说明的是:如何统计每一行中小于mid的数,我们使用的是Math.min(mid / i, n)
,来统计每一行的个数。
解释:mid / i, 就是使用mid 除以 行号,即为用mid除以一个乘数(行),得到另一个乘数(列),这个列所在的位置及其之前的数,都是小于等于mid的数,累加列数即可;特别的如果 mid / n > n,即mid很大,除完之后发现超出了列数,所以说明这一行都是小于mid的,累加mid即可
代码实现
class Solution {
public int findKthNumber(int m, int n, int k) {
int left = 1;
int right = m * n + 1;
while(left < right) {
int mid = left + (right - left) / 2;
int count = 0;
// 统计每一行中小于mid的数字数量
for(int i = 1; i <= m; i++) {
count += Math.min(mid / i, n);
}
if(count >= k) {
right = mid;
} else {
left = mid + 1;
}
}
return right;
}
}