乘法表中第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=9*10^8,不可取。

          二分思想,二分枚举第k小的数mid, mid的值初始一定在[1, m*n]之间。统计乘法表中小于等于mid的元素个数,这里如果还是简单遍历的话,复杂度O(m*n),需要一种快速的方法。

从第一行i=1开始遍历,这一行满足小于等于mid的元素有min(mid/1, n)个,类似的,第二行满足条件的元素有min(mid/2, n),...第i行有min(mid/i, n),遍历到min(mid, m)行即可,后面的满足条件的元素均为0,不用考虑。

class Solution {
public:
    int findKthNumber(int m, int n, int k) {
        int low = 1, high = m*n, mid, cnt;
        while (low<high)  //循环结束low=high指向第k小的元素
        {
            mid = low + (high-low)/2;
            cnt = 0;
            for (int i=1; i<=min(m, mid); ++i)
                cnt += min(mid/i, n);
            if (cnt<k)
                low = mid + 1;  //low指向结果所在区间左边界
            else
                high = mid;    //high指向有边界
        }
        return high;
    }
};

这里需要格外注意二分循环条件和边界的更新。 

注意:

       m 和 n 的范围在 [1, 30000] 之间。

       k 的范围在 [1, m * n] 之间。

 

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/kth-smallest-number-in-multiplication-table


版权声明:本文为weixin_38730718原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。