Given a sorted integer array arr, two integers k and x, return the k closest integers to x in the array. The result should also be sorted in ascending order.
Since the array is sorted, we can use binary search to find the position closest to x. Then, we expand outwards using two pointers (left and right) to collect the k closest elements. At each step, we compare which side is closer to x and move the pointer accordingly.
from bisect import bisect_left
from typing import List
classSolution:
deffindClosestElements(self, arr: List[int], k: int, x: int) -> List[int]:
n = len(arr)
idx = bisect_left(arr, x)
left, right = idx -1, idx
res = []
while k >0:
if left <0:
right +=1elif right >= n or abs(arr[left] - x) <= abs(arr[right] - x):
left -=1else:
right +=1 k -=1return arr[left+1:right]
import java.util.*;
classSolution {
public List<Integer>findClosestElements(int[] arr, int k, int x) {
int n = arr.length;
int left = 0, right = n - 1;
while (right - left >= k) {
if (Math.abs(arr[left]- x) > Math.abs(arr[right]- x)) {
left++;
} else {
right--;
}
}
List<Integer> res =new ArrayList<>();
for (int i = left; i <= right; i++) {
res.add(arr[i]);
}
return res;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<vector>#include<cmath>usingnamespace std;
classSolution {
public: vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int left =0, right = arr.size() -1;
while (right - left >= k) {
if (abs(arr[left] - x) > abs(arr[right] - x)) {
left++;
} else {
right--;
}
}
return vector<int>(arr.begin() + left, arr.begin() + right +1);
}
};
⏰ Time complexity: O(n), where n is the length of arr. In the worst case, we scan the array once.
🧺 Space complexity: O(1) (excluding the output list).
src -[6]
it means A[mid + 1] - A[mid + k] is better than A[mid] - A[mid + k - 1],
and we have mid smaller than the right i.
So assign left = mid + 1.
Method 2 – Binary Search for Window Start (No Math.abs)#
Let f[i] = abs(x - arr[i]), where 0 <= i < n. We want to find the starting index startIdx such that the window arr[startIdx...startIdx+k-1] contains the k closest elements to x. Since the array is sorted, we can use binary search to find the leftmost startIdx where the window is optimal.
Assume we are taking A[i] ~ A[i + k -1]. We binary search for i, and compare the distance between x - A[mid] and A[mid + k] - x:
1
2
3
4
5
6
7
8
9
10
11
case 1: x - A[mid] < A[mid + k] - x, need to move window go left
-------x----A[mid]-----------------A[mid + k]----------
case 2: x - A[mid] < A[mid + k] - x, need to move window go left again
-------A[mid]----x-----------------A[mid + k]----------
case 3: x - A[mid] > A[mid + k] - x, need to move window go right
-------A[mid]------------------x---A[mid + k]----------
case 4: x - A[mid] > A[mid + k] - x, need to move window go right
-------A[mid]---------------------A[mid + k]----x------
If x - A[mid] > A[mid + k] - x,
it means A[mid + 1] ~ A[mid + k] is a better window than A[mid] ~ A[mid + k - 1],
so assign left = mid + 1.
Note: You should not compare the absolute value of abs(x - A[mid]) and abs(A[mid + k] - x). This fails for cases like A = [1,1,2,2,2,2,2,3,3], x = 3, k = 3.
import java.util.*;
classSolution {
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<vector>usingnamespace std;
classSolution {
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) /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);
}
};