Example 1
ready- Input
arr = [ 1, 2, 3, 4, 5 ] k = 4 x = 3- Expected
[ 1, 2, 3, 4 ]- Why
- 1 and 5 tie in distance, so the smaller value 1 stays
A sorted price list can contain 100,000 entries, yet a shopper may want only the k
prices nearest a budget x. Sorting those prices by closeness would throw away the
most useful fact you were given: they're already in order.
Given a non-decreasing integer array arr, return the k values closest to x. Return
those values in ascending order.
Value a is closer than value b when:
|a - x| < |b - x|, ora < b.The answer always forms a contiguous window, meaning one uninterrupted slice of
arr. Duplicate values are allowed and occupy separate positions.
1 <= k <= arr.length <= 100_000arr is sorted in non-decreasing order.-1_000_000_000 <= arr[i], x <= 1_000_000_000Hints
Compare the two endpoints. Whichever endpoint is farther from x can't belong to
the final window. On a tie, remove the larger right endpoint.
A size-k answer can start only from index 0 through arr.length - k. Binary-search
that range for the first valid left edge.
For a window starting at mid, compare x - arr[mid] with
arr[mid + k] - x. If the left value is farther, shift the window right. A tie
stays left because the smaller value wins.
Can you explain why the closest values must be contiguous before writing either solution? That proof is the reason binary search is available here.
Visible cases
arr = [
1,
2,
3,
4,
5
]
k = 4
x = 3[
1,
2,
3,
4
]arr = [
1,
2,
3,
4,
5
]
k = 4
x = -1[
1,
2,
3,
4
]arr = [
1,
2,
3,
4,
5
]
k = 4
x = 6[
2,
3,
4,
5
]Interview signal
The answer is one sorted window. Start with the whole array and discard one endpoint at
a time until exactly k values remain.
If the endpoints are equally far from x, discard the right one: it's larger, while
the tie rule favors the smaller value.
def find_closest_elements(arr: list[int], k: int, x: int) -> list[int]:
left, right = 0, len(arr) - 1
while right - left + 1 > k:
left_distance = abs(arr[left] - x)
right_distance = abs(arr[right] - x)
if left_distance <= right_distance:
right -= 1
else:
left += 1
return arr[left:right + 1]Sorted order makes this safe. If the left endpoint loses to the right endpoint, it also
loses to every value between them on the route toward x; the symmetric argument
handles the right endpoint.
Time O(n), space O(k) for the returned slice, with O(1) auxiliary space.
There are n - k + 1 possible size-k windows. Search their left-edge indices from
0 through n - k.
At candidate mid, only two values decide whether the best window lies farther right:
arr[mid], the value you would drop by shifting right, andarr[mid + k], the value you would gain.If the left value is farther from x, shift right. Otherwise keep this window or search
left; equality stays left to honor the smaller-value tie rule.
def find_closest_elements(arr: list[int], k: int, x: int) -> list[int]:
left, right = 0, len(arr) - k
while left < right:
mid = (left + right) // 2
if x - arr[mid] > arr[mid + k] - x:
left = mid + 1
else:
right = mid
return arr[left:left + k]The comparison also works when x sits outside the array: one side becomes negative,
which drives the search toward the nearest end.
Time O(log(n − k) + k), space O(k) for the returned slice, with O(1) auxiliary space.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[ 1, 2, 3, 4 ]