[LeetCode] Find K Closest Elements 尋找K個最近元素
Given a sorted array, two integers k
and x
, find the k
closest elements to x
in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example 1:
Input: [1,2,3,4,5], k=4, x=3 Output: [1,2,3,4]
Example 2:
Input: [1,2,3,4,5], k=4, x=-1 Output: [1,2,3,4]
Note:
- The value k is positive and will always be smaller than the length of the sorted array.
- Length of the given array is positive and will not exceed 104
- Absolute value of elements in the array and x will not exceed 104
這道題給我們了一個數組,還有兩個變數k和x。讓我們找陣列中離x最近的k個元素,而且說明了陣列是有序的,如果兩個數字距離x相等的話,取較小的那個。從給定的例子可以分析出x不一定是陣列中的數字,我們想,由於陣列是有序的,所以最後返回的k個元素也一定是有序的,那麼其實就是返回了原陣列的一個長度為k的子陣列,轉化一下,實際上相當於在長度為n的陣列中去掉n-k個數字,而且去掉的順序肯定是從兩頭開始去,因為距離x最遠的數字肯定在首尾出現。那麼問題就變的明朗了,我們每次比較首尾兩個數字跟x的距離,將距離大的那個數字刪除,直到剩餘的陣列長度為k為止,參見程式碼如下:
解法一:
class Solution { public: vector<int> findClosestElements(vector<int>& arr, int k, int x) { vector<int> res = arr; while (res.size() > k) { int first = 0, last = res.size() - 1; if (x - res.front() <= res.back() - x) { res.pop_back(); }else { res.erase(res.begin()); } } return res; } };
下面這種解法是論壇上的高分解法,用到了二分搜尋法。其實博主最開始用的方法並不是帖子中的這兩個方法,雖然也是用的二分搜尋法,但博主搜的是第一個不小於x的數,然後同時向左右兩個方向遍歷,每次取和x距離最小的數加入結果res中,直到取滿k個為止。但是下面這種方法更加巧妙一些,二分法的判定條件做了一些改變,就可以直接找到要返回的k的數字的子陣列的起始位置,感覺非常的神奇。每次比較的是mid位置和x的距離跟mid+k跟x的距離,以這兩者的大小關係來確定二分法折半的方向,最後找到最近距離子陣列的起始位置,參見程式碼如下:
解法二:
class Solution { public: vector<int> findClosestElements(vector<int>& arr, int k, int x) { int left = 0, right = arr.size() - k; while (left < right) { int mid = left + (right - left) / 2; if (x - arr[mid] > arr[mid + k] - x) left = mid + 1; else right = mid; } return vector<int>(arr.begin() + left, arr.begin() + left + k); } };
參考資料: