题目
几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第k小的数字吗?
给定高度m 、宽度n 的一张 m * n的乘法表,以及正整数k,你需要返回表中第k 小的数字。
示例
例 1:
输入: m = 3, n = 3, k = 5 输出: 3 解释: 乘法表: 1 2 3 2 4 6 3 6 9
第5小的数字是 3 (1, 2, 2, 3, 3).
例 2:
输入: m = 2, n = 3, k = 6 输出: 6 解释: 乘法表: 1 2 3 2 4 6
第6小的数字是 6 (1, 2, 2, 3, 4, 6)
注意: m 和 n 的范围在 [1, 30000] 之间。 k 的范围在 [1, m * n] 之间。
思路
首先:涉及元素极多做不到遍历的二维矩阵里的第K小都可以用二分猜答案的套路,转化为“给定一个数,求矩阵中有多少个数比这个数小”,进而实现二分查找 本题题解:
- 与常见二分不同点在于:本题二分是把值来当作边界,而不是下标作为边界
- 获得在 m * n 乘法表中,找出每行有多少个值小于等于num, 其中每行的值为 i * j (i代表当前行,j代表当前列),通过 num // i 来获取每行小于等于 num 值的总个数
- 乘法表 m * n 最小是1,最大是m * n, 通过提前判断加速算法
- 由于目标值可能存在重复边界情况,需要注意不同条件的等号判定
题解
class Solution:
def findKthNumber(self, m: int, n: int, k: int) -> int:
if k == 1:
return 1
if k == m * n:
return m * n
left, right = 1, m * n
while left < right:
mid = left + ((right - left) >> 2)
if self.countsum(m, n, mid) >= k:
right = mid
else:
left = mid + 1
return left
def countsum(self, m, n, mid):
return sum(min(mid // i, n) for i in range(1, m + 1))
|