5.18打卡:剑指 offer两题:最小k个数/整数1出现的次数

最小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;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章