My PriorityQueue solution, the time complexity is O(n+klog(k)) = O(nlog(n)).
class IndexDistance{ int index; int distance; public IndexDistance(int a, int b){ this.index = a; this.distance = b; } } public List<Integer> findClosestElements(int[] arr, int k, int x) { PriorityQueue<IndexDistance> pq = new PriorityQueue<>((a,b)->a.distance==b.distance?a.index-b.index:a.distance-b.distance); int n = arr.length; int[] distances = new int[n]; for(int i=0;i<arr.length;i++){ distances[i]=Math.abs(arr[i]-x); pq.offer(new IndexDistance(i, distances[i])); } List<Integer> res = new ArrayList<>(); for(int i=0;i<k;i++){ res.add(arr[pq.poll().index]); } Collections.sort(res); return res; }
The Binary Search Solution, the mid ~ mid+k is a sliding widonw, they have 4 conditions with x:
1. x...arr[mid]...arr[mid+k] x-arr[mid]<arr[mid+k]-x -> right=mid
2. arr[mid]...x......arr[mid+k] x-arr[mid]<arr[mid+k]-x -> right=mid
3. arr[mid]......x...arr[mid+k] x-arr[mid]>. arr[mid+k]-x left=mid +1
4. arr[mid]...arr[mid+k]...x x-arr[mid]>. arr[mid+k]-x left=mid +1
At last, left = right, the window left ~ left+k is the result.
public List<Integer> findClosestElements(int[] arr, int k, int x) { int left = 0, right = arr.length - k; while (left < right) { int mid = (left + right) / 2; if (x - arr[mid] > arr[mid + k] - x) left = mid + 1; else right = mid; } List<Integer> res = new ArrayList<>(); for(int i=left;i<left+k;i++){ res.add(arr[i]); } return res; }