题目:
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
UPDATE (2017/9/19):
The arr parameter had been changed to an array of integers (instead of a list of integers). Please reload the code definition to get the latest changes.
思路:
我们定义两个指针left和right,其中left初始化为小于x的第一个数,right初始化为大于等于x的第一个数,然后分别比较left和right与x的差值,如果left与x的差值小,则将left加入结果集中,并将left左移;否则将right加入结果集中,并将right右移。这样迭代直到结果集的大小达到k。当然我们还需要随时判断left和right是否已经到达数组的边界(我们在实现中,用arr.end()作为哨兵,判断left和right是否到达边界)。为了防止排序,我们定义ret1和ret2,其中ret1中存放比x小的所有数,而ret2中存放比x大的所有数,这样最后将ret1逆序,并且和ret2相连接就可以了。算法的时间复杂度可以控制在O(logn + k)之内。
代码:
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
vector<int> ret1, ret2;
vector<int>::iterator left, right;
right = lower_bound(arr.begin(), arr.end(), x);
left = right;
if (left == arr.begin()) {
left = arr.end();
}
else {
--left;
}
while (ret1.size() + ret2.size() < k) {
int diff1 = left == arr.end() ? INT_MAX : x - *left;
int diff2 = right == arr.end() ? INT_MAX : *right - x;
if (diff1 <= diff2) {
ret1.push_back(*left);
if (left == arr.begin()) {
left = arr.end();
}
else {
--left;
}
}
else {
ret2.push_back(*right);
if (right != arr.end()) {
++right;
}
}
}
reverse(ret1.begin(), ret1.end());
ret1.insert(ret1.end(), ret2.begin(), ret2.end());
return ret1;
}
};