最小k个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
class Solution {
public:
void AdjustHeap(vector<int> &input, int i, int len){
//i是指从第i个结点开始调整,len是指调整范围0-len
int child = 2*i + 1;
int temp = input[i];
//递归调整法
if(child < len){//当孩子节点还在调整范围内才可以调整,使用下沉调整
//把大的数下沉
if(child + 1 < len && input[child + 1] > input[child]){
child = child + 1;
}
if(input[i] < input[child]){
swap(input[i], input[child]);
AdjustHeap(input, child, len);
}
}
}
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
if(input.empty() || k > input.size() || k == 0) return res;
//建堆
//算法的思想为维持一个大小为k的最大堆,再对k以后的元素进行遍历,如果有元素比堆顶的元素小的,则交换
//并且继续调整维持最大堆,这样当遍历完所有元素之后,最大堆里的k个数就是原数组最小的k个数
//该算法利用最大堆只是为了方便获取最大堆里的最大的元素,并不完全利用堆排序,另一种解法也可以利用堆排序排序完以后再取前k个数
for(int i = (k - 1)/2; i >= 0; i--)
{
//AdjustHeap(input, i. k);
AdjustHeap(input, i, k);
}
//for(int i = (k - 1)/2); i >= 0; i --)
int i = k;
while(i < input.size())
{
if(input[0] > input[i])
{
swap(input[0],input[i]);
AdjustHeap(input, 0, k);
}
i ++;
}
for(int i = 0; i < k; i ++) res.push_back(input[i]);
return res;
}
};
整数1出现的次数
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路:
分别计算个位、十位、百位........上出现 1 的个数。以 n =216为例:个位上: 1 ,11,21,31,.....211。个位上共出现(216/10)+ 1个 1 。因为除法取整,210~216间个位上的1取不到,所以我们加8进位。你可能说为什么不加9,n=211怎么办,这里把最后取到的个位数为1的单独考虑,先往下看。十位上:10~19,110~119,210~216. 十位上可看成 求(216/10)=21 个位上的1的个数然后乘10。这里再次把最后取到的十位数为1的单独拿出来,即210~216要单独考虑 ,个数为(216%10)+1 .这里加8就避免了判断的过程。后面以此类推。时间复杂度 O(logN)
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int cnt = 0;
for (int m = 1; m <= n; m *= 10)
{
int a = n / m, b = n % m;
//因为除法取整,210~216间个位上的1取不到,所以我们加8进位
cnt += (a + 8) / 10 * m + (a % 10 == 1 ? b + 1 : 0);
}
return cnt;
}
};