思路
二分查找。首先二分查找到最后一个<=target的位置,并将left设置为该位置,right为该位置+1,然后根据left和right与target的差值得到left和right指针移动的条件(left和right指针都指向下一个位置,可以从k的初始化看出来)。最后将[left+1, right-1]内的元素依次存入arraylist即可。
时间复杂度O(logn+k)
空间复杂度O(1)
注意:lintcode460与本题唯一不同的是输出不需要排序
代码
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int left = findLowerClosest(arr, x);
int right = left + 1;
List<Integer> res = new ArrayList<>();
for (int i = 0; i < k; i++) {
if (isLeftCloser(arr, x, left, right)) {
left--;
} else {
right++;
}
}
for (int i = left + 1; i < right; i++) {
res.add(arr[i]);
}
return res;
}
private boolean isLeftCloser(int[] arr, int target, int left, int right) {
if (left < 0) {
return false;
}
if (right >= arr.length) {
return true;
}
if (target - arr[left] != arr[right] - target) {
return target - arr[left] < arr[right] - target;
}
return true;
}
private int findLowerClosest(int[] arr, int x) {
int start = 0, end = arr.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (arr[mid] == x) {
start = mid;
} else if (arr[mid] < x) {
start = mid;
} else {
end = mid;
}
}
if (arr[end] <= x) {
return end;
}
if (arr[start] <= x) {
return start;
}
return 0;
}
}