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