title: 每日一練(21):最小的k個數
categories:[劍指offer]
tags:[每日一練]
date: 2022/02/17
每日一練(21):最小的k個數
輸入整數陣列 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。
示例 1:
輸入:arr = [3,2,1], k = 2
輸出:[1,2] 或者 [2,1]
示例 2:
輸入:arr = [0,1,2,1], k = 1
輸出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/probl...
方法一:sort排序
思路和演算法
對原陣列從小到大排序後取出前 k 個數即可。
複雜度分析
- 時間複雜度:O(n logn),其中 n 是陣列 arr 的長度。演算法的時間複雜度即排序的時間複雜度。
- 空間複雜度:O(logn),排序所需額外的空間複雜度為 O(logn)。
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> ans(k, 0);
if (arr.size() == 0 || k == 0) {
return ans;
}
sort(arr.begin(), arr.end()); //排序
for (int i = 0; i < k; i++) {
ans.push_back(arr[i]); //新增到目標vector
}
return ans;
}
方法二:堆
思路和演算法
我們用一個大根堆實時維護陣列的前 k 小值。首先將前 k 個數插入大根堆中,隨後從第 k+1 個數開始遍歷,如果當前遍歷到的數比大根堆的堆頂的數要小,就把
堆頂的數彈出,再插入當前遍歷到的數。最後將大根堆裡的數存入陣列返回即可。在下面的程式碼中,由於 C++ 語言中的堆(即優先佇列)為大根堆,我們可以這
麼做。而 Python 語言中的堆為小根堆,因此我們要對陣列中所有的數取其相反數,才能使用小根堆維護前 k 小值。
複雜度分析
- 時間複雜度:O(n logk),其中 nn 是陣列 arr 的長度。由於大根堆實時維護前 k 小值,所以插入刪除都是 O(logk) 的時間複雜度,最壞情況下陣列裡 n 個數都會插入,所以一共需要 O(nlogk) 的時間複雜度。
- 空間複雜度:O(k),因為大根堆裡最多 k 個數。
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> ans(k, 0);
if (arr.size() == 0 || k == 0) {
return ans;
}
priority_queue<int> q;
for (int i = 0; i < k; ++i) { //將前k個數插入堆中
q.push(arr[i]);
}
for (int i = 0; i < (int)arr.size(); ++i) {
if (q.top() > arr[i]) { //第 k+1 個數開始遍歷,如果當前遍歷到的數比大根堆的堆頂的數要小,就把
q.pop(); //堆頂的數彈出,再插入當前遍歷到的數
q.push(arr[i]);
}
}
for (int i = 0; i < k; ++i) {
ans[i] = q.top(); //把堆中的數存到目標vector中
q.pop();
}
return ans;
}