https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/description/
一、题目:
给出一个 m*n 的乘法表,然后求出第k大的数字。
二、分析:
1、最开始的思路,是便利一下 m*n, 然后用 map 容器把每个节点出现的个数保存起来, map[node]++; 结果超时。
2、用Bs,进行查找,在 1~m*n 之间进行二分查找,如果 1~mid 之间不大于 k 的节点的个数大于 k, 则继续二分左半部分;反之,二分右半部分。
其中最为纠结的就是在二分的时候,如何判断一个居间内 不大于 k 的节点个数。
三、map 容器的超时代码:
#include<iostream>
#include <map>
using namespace std;
#define MaxLen 30010
class Solution {
public:
int findKthNumber(int m, int n, int k) {
map<int, int>_map;
_map.clear();
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
int tmp = 0;
if(i==1){
tmp = j;
}else if(j==1){
tmp = i;
}else{
tmp = i*j;
}
_map[tmp]++;
}
}
int ans = 0;
for(map<int ,int>::iterator iter = _map.begin(); iter!=_map.end(); iter++){
ans += iter->second;
if(ans>=k){
ans = iter->first;
break;
}
}
cout<<ans<<endl;
return ans;
}
};
int main(){
int m, n, k;
map<int, int>_m;
cin>>m>>n>>k;
Solution s;
s.findKthNumber(m, n, k);
return 0;
}
四、Bs 的Ac 代码:
#include<iostream>
#include <map>
using namespace std;
#define MaxLen 30010
class Solution {
public:
//获取不大于k 的节点的个数
int getSmallerNum(int m, int n, int value){
int ans = 0;
for(int i=1; i<=m; i++){
ans += min(n, value/i);
}
return ans;
}
int findKthNumber(int m, int n, int k) {
if(k==m*n) return k;
int left = 1, right = m*n;
int ans = 0;
while(left<=right){
int mid = (right-left)/2 + left;
int num = getSmallerNum(m, n, mid);
if(num>=k){
ans = mid;
right = right-1;
}else{
left = left+1;
}
}
cout<<ans<<endl;
return ans;
}
};
int main(){
int m, n, k;
cin>>m>>n>>k;
Solution s;
s.findKthNumber(m, n, k);
return 0;
}