开启我的LeetCode刷题日记:668. 乘法表中第k小的数

66 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

编程世界总是离不了算法

最近在看框架源码时,会有很多算法的实现逻辑,有时候会感到吃力

于是决定蹭着假期,加强算法和数据结构相关的知识

那怎么提升呢?

其实我知道算法这东西没有捷径,多写多练才能提升,于是我开启我的LeetCode刷题之旅

第一阶段目标是:200道,每天12

为了不乱,本系列文章目录分为三部分:

  1. 今日题目:xxx
  2. 我的思路
  3. 代码实现

今日题目:668. 乘法表中第k小的数

几乎每一个人都用 乘法表。但是你能在乘法表中快速找到第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] 之间。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/kt… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路

假设给的的乘法表是 33 的,我们要找第 5小的数,如果乘法表中小于等于 3 的数字有 5 个,那么3是在这个乘法表中一定是第5小的。当然3也可以是第4小的,即在33的乘法表中 3 最大是第 5 小的,还可以再小。 记乘法表中小于 mid 的数字有 smallerCount 个。

  • smallerCount < k ,mid 最大情况不足 第k小,因此 将mid及小于mid的数在区间中剔除,left = mid+1
  • smallerCount >= k,mid 最大情况 比k大,但是!!但是乘法表中可能有很多个 mid,所有mid需要保,比mid大的数字在区间中剔除,right = mid

代码实现

/**
 * @param {number} m
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
var findKthNumber = function (m, n, k) {
    let left = 1, right = m * n;
    while (left < right) {
        const mid = left + ((right - left) >> 1);
        console.log(left, right, mid)
        if (smallerCount(m, n, mid) >= k) {
            // 细节:二分查找过程中取得的值不一定在乘法表中,所有在 smallerCount = k的时候不能直接retun mid;
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    // 此时有 left === right,区间缩为一个点,即为答案
    return left;
};

// 辅助函数
/**
 * 统计乘法表中有多个数字小于等于 num
 * @param {number} m - 乘法表的高度
 * @param {number} n - 乘法表的宽度
 * @param {number} num
 * @param {number} count - m*n乘法表中小于等于 num 的数字数量,即在m*n的乘法表中 num 最多是第 count 小的
 */
const smallerCount = function (m, n, num) {
    let count = 0;
    // 统计第i行小于 num 的数目
    for (let i = 1; i <= m; i++) {
        count += Math.min(Math.floor(num / i), n);
    }
    return count;
}

总结

实现方式其实有很多,这里仅供参考~

由于刚开始刷题,也不知道从哪里刷好,如果前辈们有好的建议,希望不吝赐教,感谢🌹