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) { 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); } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/658
類似題目:
Guess Number Higher or Lower II
Find K-th Smallest Pair Distance
參考資料:
https://leetcode.com/problems/find-k-closest-elements/