乘法表中第k小的数

时间:2022-07-26
本文章向大家介绍乘法表中第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)
链接:https://leetcode-cn.com/problems/kth-smallest-number-in-multiplication-table
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解决方案

由于m和n范围为3e4,m*n为9e8,因此将所有数字得到排序的算法是不满足要求的。

对于该问题假设我们已经知道了一个数记做target,target的上界为m * n,下界为1,只需统计乘法表中不大于target元素的数目与k相比即可。随着target值的增长得到的元素数目亦是增长,因此可以使用二分查找的方式。该问题就可以转化为找到元素数目大于等于k的最小target。

给定target统计乘法表中不大于target的元素数目,从乘法表的右上角开始,若当前值大于target,左移;否则加上以当前位置结尾的横向序列长度并下移。

class Solution {
    public int findKthNumber(int m, int n, int k) {
        int right = m * n;
        int left = 1;
        // 找到满足条件的最小的 这是由于某个乘法表中不存在的数亦会使得count = k
        while(left < right){
            int mid = left + (right - left) / 2;
            if(count(m, n, mid) < k){
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        return left;
    }
    // 找到小于等于target的元素数目
    public int count(int m, int n, int target){
        int i = 1;
        int j = n;
        int ans = 0;
        while(i <= m && j >= 1){
            if(i * j > target){
                j--;
            }else{
                ans += j;
                i++;
            }
        }
        return ans;
    }
}

二分的时间复杂度为O(log(m * n)),统计的时间复杂度为O(m + n)总体时间复杂度为O((m + n )* log(m * n));