题目描述
大意:求解第k小的组合数
算法一:set+组合数
算法思路
- 以下是1-12的组合数的图
- 通过图片我们可以发现C(i,0)=C(i,i)=1
- 因为还有的组合数重复,所以我们用set来去重
- 故我们可以用一个set来维护这些组合数的大小,但是计算的时候就不重复插入1
- 将所有的组合数插入到set中,最后返回set中第k小的数
- 计算组合数时,我们只需要计算底数≤i的即可
- 求解单个组合数,Cnk分子分母约分后,可以在O(k)的复杂度求出来
代码实现
class Solution {
public:
int C(int n, int k) //计算组合数C(n,k),n个里面取k个
{//时间复杂度O(k)
long long res = 1;
for (int i = n; i >= n - k + 1; i -- ) //计算分子
res *= i;
for (int i = 1; i <= k; i ++ ) //除去分母
res /= i;
return res; //返回答案
}
int kthSamllest(int k) {
set<int> s;
s.insert(1);
for (int i = 2; i <= k; i ++ ) //插入所有底小于等于k的组合数
for (int j = 1; j <= i / 2; j ++ ) //C(i,0)=C(i,i)=1
//故不需要重复插
s.insert(C(i,j));
int cnt = 0;
for(auto it : s)
{
cnt ++ ;
if(cnt == k) return it; //第k小的组合数
}
return 0;
}
};
复杂度分析
- 时间复杂度,求解单个组合数的时间复杂度为O(j),对于数i,需要求解2i个组合数,∑i=2k∑j=1⌊2i⌋j=2∑i=1ki(k−i)=2k∑i−2∑i2=2k∗2k(k+1)−2∗6k(k+1)(2k+1)=O(k3),计算所有的组合数的时间复杂度为O(k3),set中插入的复杂度为logn,所以将所有组合数放入set中的复杂度为O(k3logk3)=O(3k3logk)=O(k3logk),set中查询的复杂度为O(logn),但是遍历的复杂度为O(n),我们只遍历了前k个数,所以时间复杂度为O(k),总得时间复杂度为O(k3logk+k)=O(k3logk)级别
- 空间复杂度,为set内元素的规模,为O(k3)级别。
算法二:数学分析法
算法思路
- 我们再仔细分析这张图片………………
- 其实这题很好发现Ck1=Ckk−1=k
- 所以,其实我们直接
return k;
即可
代码实现
class Solution {
public:
int kthSamllest(int k) {
return k;
}
};
复杂度分析
- 时间复杂度,O(1)
- 空间复杂度,O(1).